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

例如,我正在使用以下来自雅虎财经的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..

这是最有效的方法吗?考虑到在pandas中对速度的关注,我认为必须有一些特殊的函数以一种也检索索引的方式遍历值(可能通过生成器来提高内存效率)?df。不幸的是Iteritems只逐列迭代。


当前回答

Pandas基于NumPy数组。 提高NumPy数组速度的关键是一次对整个数组执行操作,而不是逐行或逐项执行。

例如,如果close是一个一维数组,你想要逐日变化的百分比,

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

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

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

所以尽量避免Python循环i, row in enumerate(…),和 考虑如何在整个数组(或数据帧)上执行运算,而不是逐行。

其他回答

你可以通过换位然后调用iteritems来遍历这些行:

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++差不多快的东西。

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

看最后一个

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(round(time.time()-A,5))

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

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

C = []
A = time.time()
for r in range(len(t)):
    C.append((t.loc[r, 'a'], t.loc[r, 'b']))
B.append(round(time.time()-A,5))

C = []
A = time.time()
[C.append((x,y)) for x,y in zip(t['a'], t['b'])]
B.append(round(time.time()-A,5))
B

0.46424
0.00505
0.00245
0.09879
0.00209

最新版本的pandas现在包含了一个用于遍历行的内置函数。

for index, row in df.iterrows():

    # do some logic here

或者,如果你想要更快,可以使用itertuples()

但是,unutbu建议使用numpy函数来避免遍历行,这会产生最快的代码。

当然,遍历数据帧的最快方法是通过df访问底层numpy ndarray。值(如您所做的那样)或通过分别访问每一列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]

不是神谕的吗?当然。但很快。

如果你想从循环中挤出更多的果汁,你会想看看cython。Cython将让你获得巨大的加速(想想10 -100倍)。检查cython的内存视图以获得最大性能。