Mup*_*pet 306 python performance for-loop dataframe pandas
我希望以顺序方式对数据框中的财务数据执行我自己的复杂操作.
例如,我使用从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
....
Run Code Online (Sandbox Code Playgroud)
然后我做以下事情:
#!/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..
Run Code Online (Sandbox Code Playgroud)
这是最有效的方式吗?鉴于对熊猫速度的关注,我认为必须有一些特殊的函数来迭代遍历值,同时也检索索引(可能通过生成器来节省内存)?df.iteritems
遗憾的是,只能逐列迭代.
Nic*_*ord 353
最新版本的pandas现在包含一个用于迭代行的内置函数.
for index, row in df.iterrows():
# do some logic here
Run Code Online (Sandbox Code Playgroud)
或者,如果你想更快地使用它 itertuples()
但是,unutbu建议使用numpy函数来避免遍历行将产生最快的代码.
unu*_*tbu 152
Pandas基于NumPy阵列.使用NumPy阵列加速的关键是一次性对整个阵列执行操作,而不是逐行或逐项执行.
例如,如果close
是1-d数组,并且您希望每日百分比更改,
pct_change = close[1:]/close[:-1]
Run Code Online (Sandbox Code Playgroud)
这将整个百分比变化数组计算为一个语句,而不是
pct_change = []
for row in close:
pct_change.append(...)
Run Code Online (Sandbox Code Playgroud)
因此,尝试for i, row in enumerate(...)
完全避免Python循环,并考虑如何使用整个数组(或数据帧)作为整体的操作来执行计算,而不是逐行.
Ric*_*ong 85
与前面提到的一样,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
Run Code Online (Sandbox Code Playgroud)
结果:
[0.5639059543609619, 0.017839908599853516, 0.005645036697387695]
Run Code Online (Sandbox Code Playgroud)
这可能不是衡量时间消耗的最佳方法,但它对我来说很快.
以下是一些利弊恕我直言:
Wes*_*ney 73
您可以通过转置然后调用iteritems来遍历行:
for date, row in df.T.iteritems():
# do some logic here
Run Code Online (Sandbox Code Playgroud)
在这种情况下,我不确定效率.为了在迭代算法中获得最佳性能,您可能希望探索在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
Run Code Online (Sandbox Code Playgroud)
我建议首先在纯Python中编写算法,确保它的工作原理并查看速度有多快 - 如果速度不够快,将事物转换为Cython就像这样,只需要很少的工作就可以得到与手工编码C一样快的东西/ C++.
Fif*_*ifi 31
你有三个选择:
按索引(最简单):
>>> for index in df.index:
... print ("df[" + str(index) + "]['B']=" + str(df['B'][index]))
Run Code Online (Sandbox Code Playgroud)
使用iterrows(最常用):
>>> for index, row in df.iterrows():
... print ("df[" + str(index) + "]['B']=" + str(row['B']))
Run Code Online (Sandbox Code Playgroud)
使用itertuples(最快):
>>> for row in df.itertuples():
... print ("df[" + str(row.Index) + "]['B']=" + str(row.B))
Run Code Online (Sandbox Code Playgroud)
三个选项显示如下:
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
Run Code Online (Sandbox Code Playgroud)
资料来源:neural-networks.io
Car*_*rst 20
只是作为一个小小的补充,如果您具有应用于单个列的复杂函数,也可以执行应用:
http://pandas.pydata.org/pandas-docs/dev/generated/pandas.DataFrame.apply.html
df[b] = df[a].apply(lambda col: do stuff with col here)
Run Code Online (Sandbox Code Playgroud)
Goi*_*Way 10
正如@joris所指出的那样,iterrows
比它慢得多itertuples
,itertuples
并且大约是100倍iterrows
,并且我在DataFrame中测试了两种方法的速度,结果是5027505记录iterrows
,它是1200it/s,并且 itertuples
是120000it/s.
如果使用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
Run Code Online (Sandbox Code Playgroud)
可以肯定的是,迭代数据帧的最快方法是通过df.values
(如您所做的那样)或分别访问每个列来访问基础的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]
Run Code Online (Sandbox Code Playgroud)
不是pythonic吗?当然。但是很快。
如果您想从循环中挤出更多汁,则需要使用cython。Cython将使您获得巨大的加速(想想10倍至100倍)。为了获得最佳性能,请检查cython的内存视图。