我已将此报告为pandas issues上的问题。 与此同时,我发布此处希望节省其他时间,以防遇到类似问题。
在分析需要优化的进程时,我发现重命名列not inplace可以提高x120的性能(执行时间)。 分析表明这与垃圾收集有关(见下文)。
此外,通过避免使用dropna方法可以恢复预期的性能。
以下简短示例演示了因子x12:
import pandas as pd
import numpy as np
%%timeit
np.random.seed(0)
r,c = (7,3)
t = np.random.rand(r)
df1 = pd.DataFrame(np.random.rand(r,c), columns=range(c), index=t)
indx = np.random.choice(range(r),r/3, replace=False)
t[indx] = np.random.rand(len(indx))
df2 = pd.DataFrame(np.random.rand(r,c), columns=range(c), index=t)
df = (df1-df2).dropna()
## inplace rename:
df.rename(columns={col:'d{}'.format(col) for col in df.columns}, inplace=True)
100个循环,最佳3:每循环15.6毫秒
%%prun
的第一个输出行:
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.018 0.018 0.018 0.018 {gc.collect}
%%timeit
np.random.seed(0)
r,c = (7,3)
t = np.random.rand(r)
df1 = pd.DataFrame(np.random.rand(r,c), columns=range(c), index=t)
indx = np.random.choice(range(r),r/3, replace=False)
t[indx] = np.random.rand(len(indx))
df2 = pd.DataFrame(np.random.rand(r,c), columns=range(c), index=t)
df = (df1-df2).dropna()
## avoid inplace:
df = df.rename(columns={col:'d{}'.format(col) for col in df.columns})
1000次循环,最佳3:每循环1.24 ms
通过避免使用dropna
方法来恢复预期的性能:
%%timeit
np.random.seed(0)
r,c = (7,3)
t = np.random.rand(r)
df1 = pd.DataFrame(np.random.rand(r,c), columns=range(c), index=t)
indx = np.random.choice(range(r),r/3, replace=False)
t[indx] = np.random.rand(len(indx))
df2 = pd.DataFrame(np.random.rand(r,c), columns=range(c), index=t)
#no dropna:
df = (df1-df2)#.dropna()
## inplace rename:
df.rename(columns={col:'d{}'.format(col) for col in df.columns}, inplace=True)
1000次循环,最佳3次:每次循环865μs
%%timeit
np.random.seed(0)
r,c = (7,3)
t = np.random.rand(r)
df1 = pd.DataFrame(np.random.rand(r,c), columns=range(c), index=t)
indx = np.random.choice(range(r),r/3, replace=False)
t[indx] = np.random.rand(len(indx))
df2 = pd.DataFrame(np.random.rand(r,c), columns=range(c), index=t)
## no dropna
df = (df1-df2)#.dropna()
## avoid inplace:
df = df.rename(columns={col:'d{}'.format(col) for col in df.columns})
1000次循环,最佳为3:每循环902μs
答案 0 :(得分:37)
这是关于github的解释的副本。
无保证 inplace
操作实际上更快。通常它们实际上是在副本上运行的相同操作,但是重新分配了顶级引用。
在这种情况下,性能差异的原因如下。
(df1-df2).dropna()
调用会创建数据帧的切片。当您应用新操作时,会触发SettingWithCopy
检查,因为可能是副本(但通常不是)。
此检查必须执行垃圾收集以清除某些缓存引用以查看它是否为副本。不幸的是,python语法使这不可避免。
首先只需制作副本就不会发生这种情况。
df = (df1-df2).dropna().copy()
后跟inplace
操作将与以前一样高效。
我个人意见:我从不使用就地操作。语法更难阅读,并没有任何优势。