[英]pandas groupby with sum() on large csv file?
我有一个大文件(19GB左右),我想在内存中加载以执行某些列的聚合。
该文件如下所示:
id, col1, col2, col3,
1 , 12 , 15 , 13
2 , 18 , 15 , 13
3 , 14 , 15 , 13
3 , 14 , 185 , 213
请注意,我在加载到数据框后使用列(id,col1)进行聚合,还要注意这些键可能会连续重复几次,例如:
3 , 14 , 15 , 13
3 , 14 , 185 , 213
对于小文件,以下脚本可以完成此任务
import pandas as pd
data = pd.read_csv("data_file", delimiter=",")
data = data.reset_index(drop=True).groupby(["id","col1"], as_index=False).sum()
但是,对于大文件,我需要在读取csv文件时使用chunksize来限制加载到内存中的行数:
import pandas as pd
data = pd.read_csv("data_file", delimiter=",", chunksize=1000000)
data = data.reset_index(drop=True).groupby(["id","col1"], as_index=False).sum()
在后一种情况下,如果(id,col1)相似的行被分成不同的文件,则会出现问题。 我该怎么处理?
编辑
正如@EdChum所指出的,有一个潜在的解决方法,即不仅将groupby结果附加到新的csv并重新读取并再次执行聚合,直到df大小不变。
但是,这有一个最糟糕的情况是未处理,即:
当所有文件(或内存无法处理的足够多的文件)在结尾处具有相同的问题类似(id,col1)时。 这将导致系统返回MemoryError
Dask.dataframe几乎可以不经修改地执行此操作
$ cat so.csv
id,col1,col2,col3
1,13,15,14
1,13,15,14
1,12,15,13
2,18,15,13
2,18,15,13
2,18,15,13
2,18,15,13
2,18,15,13
2,18,15,13
3,14,15,13
3,14,15,13
3,14,185,213
$ pip install dask[dataframe]
$ ipython
In [1]: import dask.dataframe as dd
In [2]: df = dd.read_csv('so.csv', sep=',')
In [3]: df.head()
Out[3]:
id col1 col2 col3
0 1 13 15 14
1 1 13 15 14
2 1 12 15 13
3 2 18 15 13
4 2 18 15 13
In [4]: df.groupby(['id', 'col1']).sum().compute()
Out[4]:
col2 col3
id col1
1 12 15 13
13 30 28
2 18 90 78
3 14 215 239
虽然没有人为groupby写过as_index=False
。 我们可以通过assign
解决这个问题。
In [5]: df.assign(id_2=df.id, col1_2=df.col1).groupby(['id_2', 'col1_2']).sum().compute()
Out[5]:
id col1 col2 col3
id_2 col1_2
1 12 1 12 15 13
13 2 26 30 28
2 18 12 108 90 78
3 14 9 42 215 239
我们会像你的第一个例子一样抽出大块并做groupbys。 一旦我们完成了对每个块的分组和求和,我们将收集所有中间结果并做另一个稍微不同的groupby.sum
。 这假设中间结果将适合内存。
作为一个令人愉快的副作用,这也将并行运作。
首先,您可以通过使用usecols读取csv来选择唯一常量列表 - usecols=['id', 'col1']
。 然后通过块读取csv,通过id和groupby的子集读取concat块。 更好的解释 。
如果使用列col1
更好,请更改constants = df['col1'].unique().tolist()
。 这取决于您的数据。
或者您只能读取一列df = pd.read_csv(io.StringIO(temp), sep=",", usecols=['id'])
,这取决于您的数据。
import pandas as pd
import numpy as np
import io
#test data
temp=u"""id,col1,col2,col3
1,13,15,14
1,13,15,14
1,12,15,13
2,18,15,13
2,18,15,13
2,18,15,13
2,18,15,13
2,18,15,13
2,18,15,13
3,14,15,13
3,14,15,13
3,14,185,213"""
df = pd.read_csv(io.StringIO(temp), sep=",", usecols=['id', 'col1'])
#drop duplicities, from out you can choose constant
df = df.drop_duplicates()
print df
# id col1
#0 1 13
#2 1 12
#3 2 18
#9 3 14
#for example list of constants
constants = [1,2,3]
#or column id to list of unique values
constants = df['id'].unique().tolist()
print constants
#[1L, 2L, 3L]
for i in constants:
iter_csv = pd.read_csv(io.StringIO(temp), delimiter=",", chunksize=10)
#concat subset with rows id == constant
df = pd.concat([chunk[chunk['id'] == i] for chunk in iter_csv])
#your groupby function
data = df.reset_index(drop=True).groupby(["id","col1"], as_index=False).sum()
print data.to_csv(index=False)
#id,col1,col2,col3
#1,12,15,13
#1,13,30,28
#
#id,col1,col2,col3
#2,18,90,78
#
#id,col1,col2,col3
#3,14,215,239
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.