首页 文章

使用pandas循环数据帧的最有效方法是什么?

提问于
浏览
261

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

例如,我使用从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 只是逐列迭代 .

10 回答

  • 23

    Pandas基于NumPy阵列 . 使用NumPy阵列加速的关键是一次性对整个阵列执行操作,而不是逐行或逐项执行 .

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

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

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

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

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

  • 139

    您可以通过转置然后调用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 .

  • 18

    正如@joris指出的那样, iterrowsitertuples 慢得多 itertuplesiterrows 大约100倍,我测试了数据帧中两种方法的速度,5027505记录结果是 iterrows ,它是1200it / s, itertuples 是120000it /秒 .

    如果使用 itertuples ,请注意for循环中的每个元素都是一个namedtuple,因此要获取每列中的值,可以参考以下示例代码

    >>> df = pd.DataFrame({'col1': [1, 2], 'col2': [0.1, 0.2]},
                          index=['a', 'b'])
    >>> df
       col1  col2
    a     1   0.1
    b     2   0.2
    >>> for row in df.itertuples():
    ...     print(row.col1, row.col2)
    ...
    1, 0.1
    2, 0.2
    
  • 68

    当然,迭代数据帧的最快方法是通过 df.values (正如你所做)或通过单独访问每一列 df.column_name.values 来访问底层的numpy ndarray . 由于您也想要访问索引,因此可以使用 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) . 为了获得最佳性能,请检查memory views for cython .

  • 3

    与前面提到的一样,pandas对象在一次处理整个数组时效率最高 . 然而对于那些真正需要循环通过pandas 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:最快,但无法访问该行的索引

  • 307

    最新版本的pandas现在包含一个用于迭代行的内置函数 .

    for index, row in df.iterrows():
    
        # do some logic here
    

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

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

  • 70

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

  • 3

    我注意到Nick Crawford's回答后检查了 iterrows ,但发现它产生(索引,系列)元组 . 不确定哪个最适合你,但我最终使用 itertuples 方法解决了我的问题,它产生了(index,row_value1 ...)元组 .

    还有 iterkv ,它遍历(列,系列)元组 .

  • 14

    如果你有一个复杂的函数应用于单个列,你也可以做一个小的补充:

    http://pandas.pydata.org/pandas-docs/dev/generated/pandas.DataFrame.apply.html

    df[b] = df[a].apply(lambda col: do stuff with col here)
    
  • 5

    你有三个选择:

    index(最简单):

    >>> 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']))
    

    随着itertuples(最快):

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

    三个选项显示如下:

    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
    

    资料来源:neural-networks.io

相关问题