繁体   English   中英

pandas groupby与sum()在大型csv文件上?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM