378

データフレーム内の財務データに対して独自の複雑な操作を順次実行したいと考えています。

たとえば、Yahoo Financeから取得した次の MSFT CSV ファイルを使用しています。

Date,Open,High,Low,Close,Volume,Adj Close
2011-10-19,27.37,27.47,27.01,27.13,42880000,27.13
2011-10-18,26.94,27.40,26.80,27.31,52487900,27.31
2011-10-17,27.11,27.42,26.85,26.98,39433400,26.98
2011-10-14,27.31,27.50,27.02,27.27,50947700,27.27

....

次に、次のことを行います。

#!/usr/bin/env python
from pandas import *

df = read_csv('table.csv')

for i, row in enumerate(df.values):
    date = df.index[i]
    open, high, low, close, adjclose = row
    #now perform analysis on open/close based on date, etc..

それが最も効率的な方法ですか?パンダの速度に重点を置いていることを考えると、インデックスも取得する方法で値を反復処理する特別な関数が必要であると思います (おそらく、メモリ効率を高めるためにジェネレーターを介して)。df.iteritems残念ながら、列ごとに反復するだけです。

4

12 に答える 12

412

pandas の最新バージョンには、行を反復処理するための組み込み関数が含まれるようになりました。

for index, row in df.iterrows():

    # do some logic here

または、より速く使用したい場合itertuples()

ただし、numpy 関数を使用して行の反復を回避するという unutbu の提案は、最速のコードを生成します。

于 2012-07-23T17:09:39.743 に答える
162

PandasはNumPyアレイに基づいています。NumPy配列を高速化するための鍵は、行ごとまたは項目ごとではなく、配列全体に対して一度に操作を実行することです。

たとえば、closeが1次元配列であり、日ごとのパーセント変化が必要な場合、

pct_change = close[1:]/close[:-1]

これにより、変化率の配列全体が、代わりに1つのステートメントとして計算されます。

pct_change = []
for row in close:
    pct_change.append(...)

したがって、Pythonループをfor i, row in enumerate(...)完全に回避し、行ごとではなく、配列全体(またはデータフレーム)全体に対する操作を使用して計算を実行する方法を検討してください。

于 2011-10-20T15:02:16.950 に答える
121

前述のように、pandas オブジェクトは、配列全体を一度に処理する場合に最も効率的です。しかし、私のように何かを実行するために pandas DataFrame をループする必要がある人のために、少なくとも 3 つの方法を見つけました。私は短いテストを行って、3 つのうちどれが最も時間がかからないかを確認しました。

t = pd.DataFrame({'a': range(0, 10000), 'b': range(10000, 20000)})
B = []
C = []
A = time.time()
for i,r in t.iterrows():
    C.append((r['a'], r['b']))
B.append(time.time()-A)

C = []
A = time.time()
for ir in t.itertuples():
    C.append((ir[1], ir[2]))    
B.append(time.time()-A)

C = []
A = time.time()
for r in zip(t['a'], t['b']):
    C.append((r[0], r[1]))
B.append(time.time()-A)

print B

結果:

[0.5639059543609619, 0.017839908599853516, 0.005645036697387695]

これはおそらく時間消費を測定する最良の方法ではありませんが、私にとっては速いです。

私見の長所と短所を次に示します。

  • .iterrows(): インデックスと行の項目を別々の変数で返しますが、かなり遅くなります
  • .itertuples(): .iterrows() より高速ですが、行アイテムと一緒にインデックスを返します。ir[0] はインデックスです
  • zip: 最速ですが、行のインデックスにアクセスできません

編集 2020/11/10

価値のあるものとして、他の代替手段を使用した更新されたベンチマークを次に示します (MacBookPro 2,4 GHz Intel Core i9 8 コア 32 Go 2667 MHz DDR4 でのパフォーマンス)。

import sys
import tqdm
import time
import pandas as pd

B = []
t = pd.DataFrame({'a': range(0, 10000), 'b': range(10000, 20000)})
for _ in tqdm.tqdm(range(10)):
    C = []
    A = time.time()
    for i,r in t.iterrows():
        C.append((r['a'], r['b']))
    B.append({"method": "iterrows", "time": time.time()-A})

    C = []
    A = time.time()
    for ir in t.itertuples():
        C.append((ir[1], ir[2]))
    B.append({"method": "itertuples", "time": time.time()-A})

    C = []
    A = time.time()
    for r in zip(t['a'], t['b']):
        C.append((r[0], r[1]))
    B.append({"method": "zip", "time": time.time()-A})

    C = []
    A = time.time()
    for r in zip(*t.to_dict("list").values()):
        C.append((r[0], r[1]))
    B.append({"method": "zip + to_dict('list')", "time": time.time()-A})

    C = []
    A = time.time()
    for r in t.to_dict("records"):
        C.append((r["a"], r["b"]))
    B.append({"method": "to_dict('records')", "time": time.time()-A})

    A = time.time()
    t.agg(tuple, axis=1).tolist()
    B.append({"method": "agg", "time": time.time()-A})

    A = time.time()
    t.apply(tuple, axis=1).tolist()
    B.append({"method": "apply", "time": time.time()-A})

print(f'Python {sys.version} on {sys.platform}')
print(f"Pandas version {pd.__version__}")
print(
    pd.DataFrame(B).groupby("method").agg(["mean", "std"]).xs("time", axis=1).sort_values("mean")
)

## Output

Python 3.7.9 (default, Oct 13 2020, 10:58:24) 
[Clang 12.0.0 (clang-1200.0.32.2)] on darwin
Pandas version 1.1.4
                           mean       std
method                                   
zip + to_dict('list')  0.002353  0.000168
zip                    0.003381  0.000250
itertuples             0.007659  0.000728
to_dict('records')     0.025838  0.001458
agg                    0.066391  0.007044
apply                  0.067753  0.006997
iterrows               0.647215  0.019600
于 2015-12-16T11:39:44.767 に答える
74

転置して iteritem を呼び出すことで、行をループできます。

for date, row in df.T.iteritems():
   # do some logic here

その場合の効率については確信が持てません。反復アルゴリズムで可能な限り最高のパフォーマンスを得るには、Cythonでの記述を検討したい場合があるため、次のようにすることができます。

def my_algo(ndarray[object] dates, ndarray[float64_t] open,
            ndarray[float64_t] low, ndarray[float64_t] high,
            ndarray[float64_t] close, ndarray[float64_t] volume):
    cdef:
        Py_ssize_t i, n
        float64_t foo
    n = len(dates)

    for i from 0 <= i < n:
        foo = close[i] - open[i] # will be extremely fast

最初に純粋な Python でアルゴリズムを作成し、それが機能することを確認して、その速度を確認することをお勧めします。速度が十分でない場合は、最小限の作業でこのように Cython に変換して、手作業でコーディングされた C とほぼ同じ速度のものを取得します。 /C++.

于 2011-10-21T13:04:53.253 に答える
60

次の 3 つのオプションがあります。

インデックス別(最も単純) :

>>> for index in df.index:
...     print ("df[" + str(index) + "]['B']=" + str(df['B'][index]))

iterrows を使用(最も使用されます):

>>> for index, row in df.iterrows():
...     print ("df[" + str(index) + "]['B']=" + str(row['B']))

反復あり(最速):

>>> for row in df.itertuples():
...     print ("df[" + str(row.Index) + "]['B']=" + str(row.B))

次のような 3 つのオプションが表示されます。

df[0]['B']=125
df[1]['B']=415
df[2]['B']=23
df[3]['B']=456
df[4]['B']=189
df[5]['B']=456
df[6]['B']=12

ソース: alphons.io

于 2018-02-04T09:28:16.380 に答える
25

Nick Crawfordのiterrows回答に気付いた後、チェックアウトしましたが、(インデックス、シリーズ)タプルが生成されることがわかりました。どちらが最適かはわかりませんが、(index、row_value1 ...)タプルを生成する問題のメソッドを使用することになりました。itertuples

iterkv(列、シリーズ)タプルを反復処理するもあります。

于 2012-07-29T04:53:26.230 に答える