Python 为什么数据帧的连接速度会呈指数级下降?

Python 为什么数据帧的连接速度会呈指数级下降?,python,performance,pandas,concatenation,processing-efficiency,Python,Performance,Pandas,Concatenation,Processing Efficiency,我有一个处理数据帧的函数,主要是将数据处理到bucket中,使用pd.get\u dummies(df[col])在特定列中创建特征的二进制矩阵 为了避免使用此函数一次处理所有数据(内存不足并导致iPython崩溃),我使用以下方法将大型数据帧分解为块: chunks = (len(df) / 10000) + 1 df_list = np.array_split(df, chunks) pd.get\u dummies(df)将根据df[col]的内容自动创建新列,并且df\u列表中的每个d

我有一个处理数据帧的函数,主要是将数据处理到bucket中,使用
pd.get\u dummies(df[col])
在特定列中创建特征的二进制矩阵

为了避免使用此函数一次处理所有数据(内存不足并导致iPython崩溃),我使用以下方法将大型数据帧分解为块:

chunks = (len(df) / 10000) + 1
df_list = np.array_split(df, chunks)
pd.get\u dummies(df)
将根据
df[col]
的内容自动创建新列,并且
df\u列表中的每个
df
可能会有所不同

处理后,我使用以下方法将数据帧重新连接在一起:

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()
第一个块的处理时间是完全可以接受的,但是,每个块的处理时间都会增加!这与
预处理数据(df\u块)
无关,因为它没有理由增加。这种时间增加是不是由于调用了
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中的任何其他建议

每次连接时,都会返回数据的副本

您希望保留块的列表,然后将所有内容连接起来作为最后一步

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.

切勿在for循环内调用
DataFrame.append
pd.concat
。它导致二次复制

pd.concat
返回一个新的数据帧。必须为新项目分配空间 数据帧,并且必须将旧数据帧中的数据复制到新数据帧中 数据帧。考虑循环< <代码> <代码>中的这行所需的复制量(假设每个<代码> x <代码>大小为1):

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)
而且不需要复制。现在 循环完成后,有一个对pd.concat的调用。这个电话
pd.concat
需要制作N份副本,因为
super\u x
包含
N
大小为1的数据帧。因此,当以这种方式构造时,
super\ux
需要
O(N)

副本。

Hi@unutbu,感谢您的详细解释,这确实详细解释了理论!以这种方式连接2900个这种形状的块(437173261)可行吗?处理步骤现在只需要10秒。如果在循环中使用concat,删除循环中的旧数据帧不会解决问题吗?@SantoshGupta7:问题是速度,而不是内存。无论哪种方式,峰值内存使用量都大致相同。当数据帧较大和/或循环执行多次时,复制可能是一个缓慢的操作。制作O(n^2)个拷贝的速度太慢了,因为有一个O(n)的替代方法——在循环后立即添加到列表中。将您的解决方案应用到我的具有超过1.5 M数据记录的程序中会导致执行时间从60多个小时变为不到1小时!我甚至明白为什么…!:-)谢谢
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)