在不使用 Pandas 的情况下使用 Python 处理来自 CSV 的数据

Working with data from CSV with Python without using Pandas

我对使用 python 处理 CSV 文件上的数据还很陌生。我有一个包含以下数据的 CSV 文件。我想对每个 Sprint、Jog 和 Walk 列按会话时间戳的平均值。下面的例子有主题 John Doe and Session2 and Session3 我想找到平均值分开并将它们写入新的 CSV 文件。有没有一种方法不使用 PANDAS 而使用 CSV 或 Numpy 等其他模块来按人(主题)然后按 session 收集数据。我试图制作一本字典,但键被覆盖了。我也尝试过使用列表,但我无法弄清楚如何定位会话以将它们平均化。不确定我做错了什么。我还尝试使用 dictReader 读取字段名然后处理数据,但我不知道如何对所有 John Doe Session2 数据进行分组以找到时间的平均值。

Subject, Session, Course, Size, Category, Sprint, Jog, Walk
John Doe, Session2, 17, 2, Bad, 25s, 36s, 55s
John Doe, Session2, 3, 2, Good, 26s, 35s, 45s
John Doe, Session2, 1, 2, Good, 22s, 31s, 47s
John Doe, Session3, 5, 2, Good, 16s, 32s, 55s
John Doe, Session3, 2, 2, Good, 13s, 24s, 52s
John Doe, Session3, 16, 2, Bad, 15s, 26s, 49s

PS 我说不 PANDAS 因为我的队友没有添加这个模块,因为我们有很多其他依赖项。

因为您想要按主题和 session 分组的平均值,只需根据该信息组成唯一键:

import csv
times = {}
with open('yourfile.csv', 'r') as csvfile[1:]:
    for row in csv.reader(csvfile, delimiter=','):
        key = row[0]+row[1]
        if key not in times.keys():
            times[key] = row[-3:]
        else:
            times[key].extend(row[-3:])
average = {k: sum([int(entry[:-1]) for entry in v])/len(v) for k, v in times.items()}

这假定前两个条目确实像您的示例中那样具有规则结构,并且在每行组成前两个条目时没有歧义。可以肯定的是,可以在密钥中的它们之间插入一个特殊的分隔符。 如果你也是存储数据的人:在列header中写入列的单位,可以节省后期的转换工作,避免冗余信息存储。

根据您的输入,这些内置 Python 库可以生成您想要的输出:

import csv
from itertools import groupby
from operator import itemgetter
from collections import defaultdict

with open('input.csv','r',newline='') as fin,open('output.csv','w',newline='') as fout:

    # skip needed because sample data had spaces after comma delimiters.
    reader = csv.DictReader(fin,skipinitialspace=True)

    # Output file will have these fieldnames
    writer = csv.DictWriter(fout,fieldnames='Subject Session Sprint Jog Walk'.split())
    writer.writeheader()

    # for each subject/session, groupby returns a 2-tuple of sort key and an
    # iterator over the rows of that key.  Data must be sorted by the key already!
    for (subject,session),group in groupby(reader,key=itemgetter('Subject','Session')):

        # built the row to output.  defaultdict(int) assumes integer(0) if key doesn't exist.
        row = defaultdict(int)
        row['Subject'] = subject
        row['Session'] = session

        # Count the items for average.
        count = 0
        for item in group:
            count += 1

            # sum the rows, removing the 's'
            for col in ('Sprint','Jog','Walk'):
                row[col] += int(item[col][:-1])

        # produce the average
        for col in ('Sprint','Jog','Walk'):
            row[col] /= count

        writer.writerow(row)

输出:

Subject,Session,Sprint,Jog,Walk
John Doe,Session2,24.333333333333332,34.0,49.0
John Doe,Session3,14.666666666666666,27.333333333333332,52.0

函数链接:itemgetter groupby defaultdict

如果您的数据没有预先排序,您可以使用以下替换行来读入数据并使用 groupby 中使用的相同键对数据进行排序。但是,在此实现中,数据必须足够小,以便一次将其全部加载到内存中。

    sortkey = itemgetter('Subject','Session')
    data = sorted(reader,key=sortkey)
    for (subject,session),group in groupby(data,key=sortkey):
        ...