有效地聚合具有多个int列的大型CSV文件

时间:2019-05-29 13:34:52

标签: python pandas csv dask

我有一个很大的CSV文件,其中包含一些字符串类型的列(dtype object)和其他类型的int64列。
字符串列和整数列在CSV中都可以为空。整数列中的空值表示零,而空字符串应保持为空字符串。

我想聚合所有其他列上的所有整数列。 最好的方法是什么?

输出最终应该是一个聚合的单个CSV文件。 该文件可能无法整体放入内存,这就是为什么我尝试使用Dask的原因,但是我很难理解如何执行此操作。

这是适用于内存的小型CSV的有效熊猫代码:

import pandas as pd
df = pd.read_csv("input_file.csv", na_filter=False)
df[metrics_to_aggregate] = df[metrics_to_aggregate].fillna(0).apply(pd.to_numeric)
df = df.groupby(dimensions_to_aggregate, as_index=False).sum()
df.to_csv("output_file.csv", index=False)

例如,输入df可能类似于:

  dimension1 dimension2 dimension3 metric1 metric2 metric3
0        foo        bar                  1       1
1        foo        bar                  2               2
2                   foo        bar       1       4       2
3        foo        bar     foobar               2       1

输出df应为:

  dimension1 dimension2 dimension3  metric1  metric2  metric3
0                   foo        bar        1        4        2
1        foo        bar                   3        1        2
2        foo        bar     foobar      NaN        2        1

位置:

metrics_to_aggregate=['metric1', 'metric2', 'metric3']
dimensions_to_aggregate=['dimension1', 'dimension2', 'dimension3']

1 个答案:

答案 0 :(得分:1)

如果文件未排序,则不使用大量内存就很难处理:您需要为文件中出现的每个键(维值列表)保持运行中的聚合。这样做可能是个好方法,但这取决于细节,例如存在多少可能性。可能可以分块进行处理,然后一起处理这些分块,但是您仍然需要足够的内存来存储所有当前聚集的键值。

一个简单且相当通用的解决方案是首先进行排序。 Unix sort命令将愉快地对太大而无法放入内存的文件进行排序。然后,可以轻松地对已排序的文件进行分块处理。这是显示原理的序列:您可能需要更改一些细节:

首先,我稍微扩展了文件以显示正在发生的情况,并删除了标题行(sort将被视为数据):

input_file.csv:
foo bar     1   1   
a       a   9   9   9
z   z       8   8   8
a       a   9   9   9
foo bar     2       2
    foo bar 1   4   2
foo bar foobar      2   1
z   z       7   7   7
a       a   9   9   9

然后我使用了命令:

sort input_file.csv -o input_file_sorted.csv --key=1,3

这给了我

input_file_sorted.csv
a       a   9   9   9
a       a   9   9   9
a       a   9   9   9
    foo bar 1   4   2
foo bar     1   1   
foo bar     2       2
foo bar foobar      2   1
z   z       7   7   7
z   z       8   8   8

然后我运行了这个Python程序:

import csv

number_of_dims = 3
number_of_aggs = 3

def aggregate(agg, data):
    for i,d in enumerate(data):
        if d != "":
            agg[i] += int(d)
    return

with open("input_file_sorted.csv", newline="") as f1:
    with open("output_file,csv", "w", newline="") as f2:
        csv_reader = csv.reader(f1, delimiter='\t')
        csv_writer = csv.writer(f2, delimiter='\t')
        key = None
        agg = [0] * number_of_aggs
        for l in csv_reader:
            new_key = l[:number_of_dims]
            if key is None:
                key = new_key
            if key != new_key:
                csv_writer.writerow(key + agg)
                agg = [0] * number_of_aggs
                key = new_key
            aggregate(agg, l[number_of_dims:])
        csv_writer.writerow(key + agg)

那吸引了我:

output_file.csv:
a       a   27  27  27
    foo bar 1   4   2
foo bar     3   1   2
foo bar foobar  0   2   1
z   z       15  15  15

希望有帮助!