如何在Python中流式处理和操作大型数据文件

10

我有一个相对较大(1 GB)的文本文件,我希望通过对类别进行汇总来缩小它的大小:

Geography AgeGroup Gender Race Count
County1   1        M      1    12
County1   2        M      1    3
County1   2        M      2    0

收件人:

Geography Count
County1   15
County2   23
如果整个文件可以放在内存中,这将是一个简单的问题,但使用“pandas.read_csv()”会出现“MemoryError”。因此,我一直在寻找其他方法,并且似乎有许多选项 - HDF5?使用“itertools”(这似乎很复杂-生成器?)或仅使用标准文件方法读取第一个地理位置(70行),总结计数列并在加载另外70行之前写出。

是否有人对如何做到最好有建议?我特别喜欢流式传输数据的想法,特别是因为我可以想到许多其他地方会很有用。我最感兴趣的是这种方法,或者类似地使用尽可能基本的功能。

编辑: 在这种小型情况下,我只需要按地理位置求和计数。但是,如果我可以读入一块,指定任何函数(例如将2列相加或按地理位置获取某一列的最大值),应用该函数,并在读入新块之前写出输出,则最理想不过了。


2
你知道pandas中的分块读取吗?pd.read_csv('myfile.csv', chunksize=1000)。然后你可以在循环内对每个块进行操作。 - chrisaycock
2个回答

16

你可以使用dask.dataframe,它在语法上类似于pandas,但是可以在外部执行操作,因此内存不应该成为问题:

import dask.dataframe as dd

df = dd.read_csv('my_file.csv')
df = df.groupby('Geography')['Count'].sum().to_frame()
df.to_csv('my_output.csv')

或者,如果pandas是必需的,您可以使用分块读取,如@chrisaycock所述。您可能需要尝试使用chunksize参数。

# Operate on chunks.
data = []
for chunk in pd.read_csv('my_file.csv', chunksize=10**5):
    chunk = chunk.groupby('Geography', as_index=False)['Count'].sum()
    data.append(chunk)

# Combine the chunked data.
df = pd.concat(data, ignore_index=True)
df = df.groupby('Geography')['Count'].sum().to_frame()
df.to_csv('my_output.csv')

4
我喜欢@root的解决方案,但是我会进一步优化内存使用 - 只在内存中保留聚合数据框,并仅读取您真正需要的列:
cols = ['Geography','Count']
df = pd.DataFrame()

chunksize = 2   # adjust it! for example --> 10**5
for chunk in (pd.read_csv(filename,
                          usecols=cols,
                          chunksize=chunksize)
             ):
    # merge previously aggregated DF with a new portion of data and aggregate it again
    df = (pd.concat([df,
                     chunk.groupby('Geography')['Count'].sum().to_frame()])
            .groupby(level=0)['Count']
            .sum()
            .to_frame()
         )

df.reset_index().to_csv('c:/temp/result.csv', index=False)

测试数据:

Geography,AgeGroup,Gender,Race,Count
County1,1,M,1,12
County2,2,M,1,3
County3,2,M,2,0
County1,1,M,1,12
County2,2,M,1,33
County3,2,M,2,11
County1,1,M,1,12
County2,2,M,1,111
County3,2,M,2,1111
County5,1,M,1,12
County6,2,M,1,33
County7,2,M,2,11
County5,1,M,1,12
County8,2,M,1,111
County9,2,M,2,1111

output.csv:

Geography,Count
County1,36
County2,147
County3,1122
County5,24
County6,33
County7,11
County8,111
County9,1111

使用这种方法,您可以处理大型文件。

除非您需要对数据进行排序,否则使用分块方法应该可以正常工作-在这种情况下,我会使用经典的UNIX工具,如awksort等来首先对数据进行排序。

我还建议使用PyTables(HDF5存储),而不是CSV文件-它非常快速,并允许您有条件地读取数据(使用where参数),因此非常方便并节省了很多资源,通常比CSV 快得多


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接