pandas issues の問題としてこれを報告しました。その間、他の人が同様の問題に遭遇した場合に備えて、他の時間を節約することを期待して、これをここに投稿します。
最適化が必要なプロセスをプロファイリングすると、列の名前を変更しないと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 ms
%%prun
の最初の出力行:
ncalls tottime percall cumtime percall filename:lineno(関数)
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
これはgithubの説明のコピーです。
保証なしがあり、inplace
操作が実際に高速である。多くの場合、それらは実際にはコピーで機能する同じ操作ですが、トップレベルの参照が再割り当てされます。
この場合のパフォーマンスの違いの理由は次のとおりです。
(df1-df2).dropna()
呼び出しは、データフレームのスライスを作成します。新しい操作を適用すると、これがSettingWithCopy
チェックをトリガーします。これは、couldがコピーであるためです(多くの場合、そうではありません)。
このチェックでは、ガベージコレクションを実行して、一部のキャッシュ参照を消去し、コピーであるかどうかを確認する必要があります。残念ながらpython構文はこれを不可避にします。
最初にコピーを作成するだけでは、これを実現することはできません。
df = (df1-df2).dropna().copy()
inplace
操作が続くと、以前と同じようにパフォーマンスが向上します。
私の個人的な意見:私neverインプレース操作を使用します。構文は読みにくく、利点はありません。