[Python] 用熊猫循环数据框的最有效方式是什么?


Answers

熊猫是基于NumPy阵列的。 使用NumPy数组加速的关键是一次执行整个数组的操作,而不是逐行或逐项执行。

例如,如果close是一个一维数组,并且您希望每日更改百分比,

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

这将计算整个百分比变化数组作为一个语句,而不是

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

因此,尽量避免我的Python循环for i, row in enumerate(...)完全for i, row in enumerate(...)排序,并考虑如何对整个数组(或数据框)上的操作执行计算,而不是逐行执行。

Question

我想以顺序的方式对数据框中的财务数据执行我自己的复杂操作。

例如,我正在使用以下来自雅虎财经的 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只能逐列迭代。







就像之前提到的一样,当一次处理整个数组时,熊猫对象是最有效的。 然而,对于那些真的需要通过熊猫DataFrame执行某些操作的人来说,像我一样,我发现至少有三种方法可以做到这一点。 我做了一个简短的测试,看看三者中哪一个是最不耗时的。

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:最快,但不能访问该行的索引



另一个建议是将groupby与矢量化计算相结合,如果行的子集共享允许您这样做的特征。




当然,迭代数据帧的最快方法是通过df.values (如你所做的那样)访问底层numpy ndarray,或者通过df.values访问每个列df.column_name.values来访问基础numpy df.column_name.values 。 既然你也想访问索引,你可以使用df.index.values

index = df.index.values
column_of_interest1 = df.column_name1.values
...
column_of_interestk = df.column_namek.values

for i in range(df.shape[0]):
   index_value = index[i]
   ...
   column_value_k = column_of_interest_k[i]

不pythonic? 当然。 但速度很快。

如果你想从循环中挤出更多汁液,你会想看看cython 。 Cython会让你获得巨大的加速(认为是10x-100x)。 为了获得最大性能,请查看cython的内存视图