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

400

我希望以连续的方式对数据框中的金融数据执行自己的复杂操作。

例如,我正在使用从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..

那是最有效的方式吗?鉴于pandas对速度的关注,我认为一定有一些特殊的函数可以以一种同时检索索引的方式迭代值(可能通过生成器进行内存效率)?df.iteritems不幸的是只能逐列迭代。


6
你尝试过编写一个函数并将其传递给 df.apply() 吗? - naught101
如果您想要更高的内存效率,您应该考虑使用向量化操作(使用矩阵和向量)。但是我不了解pandas,所以我无法告诉您是否可能进行这样的操作。 - mike
3
引用“unutbu”的话,NumPy似乎支持向量化操作(使用NumPy数组的关键在于一次性对整个数组执行操作,以获得更快的速度)。 - mike
1
问题特定于顺序迭代,这在金融领域非常常见,而向量化通常不可行。尼克·克劳福德的回答回答了这个问题,并额外提醒在可能的情况下使用向量化。 - Muppet
我通常不会要求提问者更改他们的接受投票,但这是一个罕见的情况,我会要求您考虑将其移动到我的答案。目前被接受的答案推荐使用iterrows(),这比最快的技术慢600倍,或者使用itertuples(),这比最快的技术慢15倍。因此,请考虑将接受的答案移动到我的答案,我在其中介绍了1倍和其他技术,并对它们进行了详细的速度测试。 - undefined
另请参阅:如何在Pandas中迭代DataFrame的行。我在那里进行了13种以上的速度测试 - undefined
13个回答

4

看最后一个

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

4
我认为遍历DataFrame最简单和有效的方式是使用numpy和numba。在这种情况下,循环可以在许多情况下达到近似于向量化操作的速度。如果不能使用numba,则普通的numpy循环很可能是下一个最佳选择。正如许多人已经指出的那样,你的默认应该是向量化,但是本答案仅考虑高效的循环,给定循环的决定,无论出于什么原因。
作为测试用例,让我们使用@DSM答案中计算百分比变化的示例。这是一个非常简单的情况,实际上你不会写一个循环来计算它,但作为基准,它提供了时间向量化方法与循环方法的合理基线。
下面我们将使用一个小的DataFrame设置4种方法,并在较大的数据集上对它们进行时间测量。
import pandas as pd
import numpy as np
import numba as nb

df = pd.DataFrame( { 'close':[100,105,95,105] } )

pandas_vectorized = df.close.pct_change()[1:]

x = df.close.to_numpy()
numpy_vectorized = ( x[1:] - x[:-1] ) / x[:-1]
        
def test_numpy(x):
    pct_chng = np.zeros(len(x))
    for i in range(1,len(x)):
        pct_chng[i] = ( x[i] - x[i-1] ) / x[i-1]
    return pct_chng

numpy_loop = test_numpy(df.close.to_numpy())[1:]

@nb.jit(nopython=True)
def test_numba(x):
    pct_chng = np.zeros(len(x))
    for i in range(1,len(x)):
        pct_chng[i] = ( x[i] - x[i-1] ) / x[i-1]
    return pct_chng
    
numba_loop = test_numba(df.close.to_numpy())[1:]

下面是一个包含100,000行数据的DataFrame的时间(使用Jupyter的%timeit函数进行计时,折叠为概要表格以提高可读性):

pandas/vectorized   1,130 micro-seconds
numpy/vectorized      382 micro-seconds
numpy/looped       72,800 micro-seconds
numba/looped          455 micro-seconds

简介:对于像这样简单的情况,为了简单明了,可以使用(向量化)pandas;要提高速度,可以使用(向量化)numpy;如果你真的需要用循环,就在numpy中使用它。如果有numba可用,则将其与numpy结合使用以获得额外的速度。在这种情况下,numpy + numba的速度几乎与向量化的numpy代码一样快。
其他细节:
- 没有展示各种选项,比如iterrows、itertuples等,它们的速度要慢很多,真的不应该使用。 - 这里的计时是相当典型的:numpy比pandas更快,向量化比循环更快,但将numba与numpy结合使用通常会极大地提高numpy的速度。 - 除了pandas选项外,所有选项都需要将DataFrame列转换为numpy数组。这个转换已包含在计时中。 - 定义/编译numpy/numba函数的时间没有包含在计时中,但对于任何大型数据框来说,它通常是可以忽略不计的。

0
那是最有效的方式吗?考虑到pandas对速度的重视,我会认为肯定有一些特殊的函数可以迭代值...
绝对有一种最有效的方式:向量化。其次是列表推导,然后是itertuples()。要远离iterrows()。它非常糟糕,比起使用常规的df["A"][i]类型的索引的原始for循环要慢得多。
我在这里详细介绍了13种方法,对它们进行了速度测试,并展示了所有的代码:如何迭代Pandas的DataFrame[有和无迭代]
我花了几个星期的时间来写这个答案。以下是结果:

enter image description here

主要要点:

  1. 如果你的目标是编写、阅读和维护起来都很容易,同时又要保持速度很快,那就使用列表推导式。它只比纯向量化慢大约10倍。
  2. 如果你的目标是尽可能快速,那就使用纯向量化。当你的公式中包含复杂的方程,如每行计算时的if语句,编写和阅读会更加困难。

像iterrows()这样的函数非常慢,比纯向量化慢大约600倍。

为了证明我测试的这13种技术在复杂的公式中也是可行的,我选择了这个非平凡的公式来通过所有的技术进行计算:

enter image description here

要获取更详细的信息以及所有13种技巧的代码,请参考我的主要答案:如何在不迭代的情况下遍历Pandas的DataFrame

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接