想象一下,您有一个包含数百万行的大型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。
谢谢,感谢您的帮助,
答案 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
现在我update
A
仅限前4行
A.update(A.iloc[:4].groupby('ID', group_keys=False).apply(fill))
A
请注意,只填充了第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
答案 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