pandas groupby和大csv文件上的sum()?

时间:2015-11-05 11:06:09

标签: python pandas

我有一个大文件(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

2 个答案:

答案 0 :(得分:8)

dask解决方案

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

如何运作

我们会像你的第一个例子一样抽出大块并做组。一旦我们对每个块进行分组和求和,我们就会将所有中间结果收集在一起并执行另一个稍微不同的groupby.sum。这假设中间结果将适合内存。

并行

作为一个令人愉快的副作用,它也将同时运作。

答案 1 :(得分:1)

首先,您可以通过usecols - Dim Filter1 = "filterword1" Dim Filter2 = "filterword2" TextBox1.Text = WebBrowser1.DocumentText TextBox2.Text = WebBrowser1.DocumentText Dim lines As New List(Of String) lines = TextBox1.Lines.ToList For i As Integer = lines.Count - 1 To 0 Step -1 If Not Regex.IsMatch(lines(i), Filter1) Then lines.RemoveAt(i) End If Next TextBox1.Lines = lines.ToArray Dim lines1 As New List(Of String) lines1 = TextBox3.Lines.ToList For i As Integer = lines1.Count - 1 To 0 Step -1 If Not Regex.IsMatch(lines1(i), Filter2) Then lines1.RemoveAt(i) End If Next TextBox1.Lines = lines1.ToArray 读取csv来选择唯一常量列表。然后通过块读取csv,通过id和groupby的子集读取concat块。 better explain

如果使用列usecols=['id', 'col1']更好,请更改col1。这取决于您的数据。

或者您只能阅读一列constants = df['col1'].unique().tolist(),这取决于您的数据。

df = pd.read_csv(io.StringIO(temp), sep=",", usecols=['id'])