如何在 python 中流入和操作大型数据文件
How to stream in and manipulate a large data file in python
我有一个相对较大 (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 列加在一起,或者按地理位置取一列的最大值),应用函数,并在读入新块之前写入输出,那将是理想的.
您可以使用 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')
我确实喜欢@root 的解决方案,但我会进一步优化内存使用 - 仅在内存中保留聚合 DF 并仅读取您真正需要的那些列:
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
PS使用这种方法你可以处理大文件。
PPS 使用分块方法应该可行,除非您需要对数据进行排序 - 在这种情况下,我会使用经典的 UNIX 工具,例如 awk
、sort
等首先对数据进行排序
我还建议使用 PyTables(HDF5 存储),而不是 CSV 文件 - 它速度非常快,允许您有条件地读取数据(使用 where
参数),所以它非常方便并节省了很多资源,通常 与 CSV 相比。
我有一个相对较大 (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 列加在一起,或者按地理位置取一列的最大值),应用函数,并在读入新块之前写入输出,那将是理想的.
您可以使用 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')
我确实喜欢@root 的解决方案,但我会进一步优化内存使用 - 仅在内存中保留聚合 DF 并仅读取您真正需要的那些列:
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
PS使用这种方法你可以处理大文件。
PPS 使用分块方法应该可行,除非您需要对数据进行排序 - 在这种情况下,我会使用经典的 UNIX 工具,例如 awk
、sort
等首先对数据进行排序
我还建议使用 PyTables(HDF5 存储),而不是 CSV 文件 - 它速度非常快,允许您有条件地读取数据(使用 where
参数),所以它非常方便并节省了很多资源,通常