我有一个处理DataFrame的函数,主要是将数据处理到存储桶中,使用pd.get_dummies(df[col])
在特定列中创建特征的二进制矩阵。
为了避免一次使用此函数处理我的所有数据(内存不足并导致iPython崩溃),我使用以下方法将大型DataFrame分解为块:
chunks = (len(df) / 10000) + 1
df_list = np.array_split(df, chunks)
pd.get_dummies(df)
会根据df[col]
的内容自动创建新列,这些列可能会因df
中的每个df_list
而有所不同。
处理完毕后,我使用以下方法将DataFrame连接在一起:
for i, df_chunk in enumerate(df_list):
print "chunk", i
[x, y] = preprocess_data(df_chunk)
super_x = pd.concat([super_x, x], axis=0)
super_y = pd.concat([super_y, y], axis=0)
print datetime.datetime.utcnow()
第一个块的处理时间是完全可以接受的,然而,它每个块增长!这与preprocess_data(df_chunk)
没有关系,因为没有理由增加它。由于调用pd.concat()
?
请参阅以下日志:
chunks 6
chunk 0
2016-04-08 00:22:17.728849
chunk 1
2016-04-08 00:22:42.387693
chunk 2
2016-04-08 00:23:43.124381
chunk 3
2016-04-08 00:25:30.249369
chunk 4
2016-04-08 00:28:11.922305
chunk 5
2016-04-08 00:32:00.357365
是否有解决方法来加快速度?我有2900个块要处理,所以任何帮助都表示赞赏!
打开Python中的任何其他建议!
答案 0 :(得分:28)
永远不要在for循环中调用DataFrame.append
或pd.concat
。它导致二次复制。
pd.concat
会返回一个新的DataFrame。必须为新的空间分配空间
DataFrame和旧DataFrame中的数据必须复制到新的DataFrame中
数据帧。考虑for-loop
中此行所需的复制量(假设每个x
的大小为1):
super_x = pd.concat([super_x, x], axis=0)
| iteration | size of old super_x | size of x | copying required |
| 0 | 0 | 1 | 1 |
| 1 | 1 | 1 | 2 |
| 2 | 2 | 1 | 3 |
| ... | | | |
| N-1 | N-1 | 1 | N |
1 + 2 + 3 + ... + N = N(N-1)/2
。因此需要O(N**2)
个副本
完成循环。
现在考虑
super_x = []
for i, df_chunk in enumerate(df_list):
[x, y] = preprocess_data(df_chunk)
super_x.append(x)
super_x = pd.concat(super_x, axis=0)
附加到列表是O(1)
操作,不需要复制。现在
循环完成后,只有一次调用pd.concat
。这个电话
由于pd.concat
包含super_x
,N
需要制作N份副本
大小为1的DataFrame。因此,当以这种方式构造时,super_x
需要O(N)
副本。
答案 1 :(得分:7)
每次连接时,都会返回数据的副本。
您希望保留一个列表,然后将所有内容连接起来作为最后一步。
df_x = []
df_y = []
for i, df_chunk in enumerate(df_list):
print "chunk", i
[x, y] = preprocess_data(df_chunk)
df_x.append(x)
df_y.append(y)
super_x = pd.concat(df_x, axis=0)
del df_x # Free-up memory.
super_y = pd.concat(df_y, axis=0)
del df_y # Free-up memory.