Groupby of splitted data(pandas)

时间:2016-08-19 21:53:23

标签: python pandas

想象一下,您有一个包含数百万行的大型CSV文件,您可以按块处理这些行。 文件太大,无法加载到内存中。什么是做groupby并应用相对“复杂”函数(如fillna)的最佳方法,而不会让块大小影响结果?我举例说明:

A = pd.DataFrame({"ID":["A", "A", "C" ,"B", "A"], "value":[3,np.nan,4,5,np.nan]})

>>> A
  ID  value
0  A      2
1  A      3
2  C      4
3  B      5
4  A      6

如果块大小为2且I groupby'ID',那么我会将前两个A分组,但将最后一个A放在一边,这会影响非直接应用函数的结果,

A.groupby('ID').fillna(method='fill')
输出将是:

   value
0    3.0
1    3.0
2    4.0
3    5.0
4    np.nan

请注意,最后一行中应该有一个np.nan,其中应该有一个3。

谢谢,感谢您的帮助,

2 个答案:

答案 0 :(得分:1)

您需要设置一种方法来记住最后一个填充值。我使用下面的字典memory

memory = {}

def fill(df):
    name = df.name
    df = df.copy()

    # fill from memory
    if name in memory.keys():
        df.iloc[0, :] = df.iloc[0, :].fillna(memory[name])

    # normal ffill
    df = df.fillna(method='ffill')

    # update memory
    memory.update({name: df.iloc[-1]})

    return df
memory

{}
A = pd.DataFrame({"ID":["A", "A", "C" ,"B", "A"], "value":[3,np.nan,4,5,np.nan]})
A

enter image description here

现在我update A仅限前4行

A.update(A.iloc[:4].groupby('ID', group_keys=False).apply(fill))
A

enter image description here

请注意,只填充了第1行中的值。排第4行。但是,让我们看一下memory

memory

{'A': ID       A
 value    3
 Name: 1, dtype: object, 'B': ID       B
 value    5
 Name: 3, dtype: object, 'C': ID       C
 value    4
 Name: 2, dtype: object}

或更具体地说memory['A']

ID       A
value    3
Name: 1, dtype: object

所以我们现在只更新A第4行

A.update(A.iloc[4:].groupby('ID', group_keys=False).apply(fill))
A

enter image description here

答案 1 :(得分:0)

我想你想要在chunk-by-chunk中读取,然后在处理后写入磁盘。我认为@ piRSquared的“保留以前看到的值的记忆”的想法应该适用,如果你要应用的函数是ffill,虽然我确定@Jeff对Dask是正确的(我不熟悉)。

我已经编了一个稍长的文件进行测试。见下文。

inputcsv = 'test.csv'
outputcsv = 'test.output.csv'
chunksize = 4

outfh = open(outputcsv, 'wb')
memory = None
len_memory = 0
#write file header to output file
pd.read_csv(inputcsv, nrows=0).to_csv(outfh, index=False)

for chunk in pd.read_csv(inputcsv, chunksize=chunksize):
    if memory is not None:
        len_memory = len(memory)
        #put memory in front of chunk
        chunk = pd.concat([memory.reset_index(), chunk], ignore_index=True)
        #ffill
    chunk['value'] = chunk.groupby('ID')['value'].fillna(method='ffill')
    #update memory
    memory = chunk.groupby('ID').last().dropna()
    #The first len_memory was from memory not input file. Get rid of them.
    chunk = chunk.iloc[len_memory:,:]
    chunk.to_csv(outfh, index=False, header=False)
outfh.close()

print pd.read_csv(inputcsv)
   ID  value
0   A    3.0
1   A    NaN
2   C    4.0
3   B    5.0
4   A    NaN
5   F    2.0
6   D    2.0
7   A    1.0
8   C    NaN
9   B    3.0
10  E    NaN
11  D    4.0
12  A    NaN
13  B    NaN
14  B    5.0
15  C    NaN
16  E    4.0
17  F    NaN
18  F    1.0
19  E    0.0

print pd.read_csv(outputcsv)
   ID  value
0   A    3.0
1   A    3.0
2   C    4.0
3   B    5.0
4   A    3.0
5   F    2.0
6   D    2.0
7   A    1.0
8   C    4.0
9   B    3.0
10  E    NaN
11  D    4.0
12  A    1.0
13  B    3.0
14  B    5.0
15  C    4.0
16  E    4.0
17  F    2.0
18  F    1.0
19  E    0.0