1. ホーム
  2. python

[解決済み] pandas iterrowsは性能に問題がありますか?

2022-08-13 08:20:18

質問

pandasからiterrowsを使用する際に、非常にパフォーマンスが悪いことに気づきました。

これは他の人が経験していることでしょうか?iterrowsに特有のもので、この関数はあるサイズのデータ(私は2~300万行を扱っています)に対しては避けるべきでしょうか?

この議論 の議論から、dataframe に dtypes が混在している場合に発生すると思われましたが、以下の簡単な例では 1 つの dtype (float64) を使用した場合でも発生することがわかります。これは私のマシンで36秒かかります。

import pandas as pd
import numpy as np
import time

s1 = np.random.randn(2000000)
s2 = np.random.randn(2000000)
dfa = pd.DataFrame({'s1': s1, 's2': s2})

start = time.time()
i=0
for rowindex, row in dfa.iterrows():
    i+=1
end = time.time()
print end - start

applyのようなベクトル化された演算は、なぜこんなに速いのでしょうか?行ごとの反復処理も行われているのでしょうね。

私の場合、iterrows を使用しない方法がわかりません (これは将来の質問のために取っておきます)。したがって、この反復を一貫して回避することができたかどうか、教えていただければ幸いです。私は別々のデータフレーム内のデータを基に計算をしています。ありがとうございます!

---編集:私が実行したいことの簡略版を以下に追加しました---。

import pandas as pd
import numpy as np

#%% Create the original tables
t1 = {'letter':['a','b'],
      'number1':[50,-10]}

t2 = {'letter':['a','a','b','b'],
      'number2':[0.2,0.5,0.1,0.4]}

table1 = pd.DataFrame(t1)
table2 = pd.DataFrame(t2)

#%% Create the body of the new table
table3 = pd.DataFrame(np.nan, columns=['letter','number2'], index=[0])

#%% Iterate through filtering relevant data, optimizing, returning info
for row_index, row in table1.iterrows():   
    t2info = table2[table2.letter == row['letter']].reset_index()
    table3.ix[row_index,] = optimize(t2info,row['number1'])

#%% Define optimization
def optimize(t2info, t1info):
    calculation = []
    for index, r in t2info.iterrows():
        calculation.append(r['number2']*t1info)
    maxrow = calculation.index(max(calculation))
    return t2info.ix[maxrow]

どのように解決するのですか?

一般的には iterrows は、非常に特殊な場合にのみ使用されるべきです。これは、様々な操作の実行に関する一般的な優先順位です。

1) vectorization
2) using a custom cython routine
3) apply
    a) reductions that can be performed in cython
    b) iteration in python space
4) itertuples
5) iterrows
6) updating an empty frame (e.g. using loc one-row-at-a-time)

Cythonのカスタムルーチンを使うのは、通常、複雑すぎるので、今は省略しましょう。

1) ベクトル化は常に、常に、最初で最良の選択です。しかし、明らかな方法でベクトル化することができない小さなケース (通常は再帰を含む) があります。さらに、小さな DataFrame では、他の方法を使用したほうが速い場合があります。

3) apply 通常 はCython空間のイテレータで処理することができます。これはpandasによって内部的に処理されますが、それは apply 式の中で何が起こっているかに依存します。例えば df.apply(lambda x: np.sum(x)) はかなり迅速に実行されるでしょう、もちろんですが。 df.sum(1) の方がより良い。しかし、次のようなものは df.apply(lambda x: x['b'] + 1) のようなものはPython空間で実行されるため、結果的にかなり遅くなります。

4) itertuples は、データをボックス化せず Series . それは単にタプルの形でデータを返すだけである。

5) iterrows DOESボックスでデータを Series . 本当に必要でない限り、他の方法を使用してください。

6) 空のフレームを一度に一行ずつ更新する。私は、この方法があまりにも多く使用されているのを見ました。これは圧倒的に遅いです。おそらく一般的な方法でしょうが(そしていくつかのpythonの構造体ではそれなりに速い)。 DataFrame はインデックスのチェックをかなり多く行うので、一度に1行ずつ更新するには常に非常に遅くなります。新しい構造体を作る方がずっと良いし concat .