向量化前瞻性函数 pandas 数据框
Posted
技术标签:
【中文标题】向量化前瞻性函数 pandas 数据框【英文标题】:vectorizing forward-looking function pandas dataframe 【发布时间】:2014-06-11 18:46:25 【问题描述】:我想对 pandas 中的 DataFrame(可以被认为是一个系列)进行“奇怪”的计算。 DataFrame 必须被视为时间序列或类似的(元素的顺序很重要)。
给定索引[i]处的值(值[i]) 给定一个步长(例如 1)[整数或实数] 给定一个乘数 rr(例如 2)[整数或实数]向前查看元素 [i:] 并为 value[i] 分配一个“类”:
+1 如果随后的值达到 value[i] + step * rr before达到 value[i] - step -1 如果随后的值达到 value[i] 的水平 - step * rr before达到 value[i] + step 0 在其他情况下(即当随后的值触摸 value[i] - step 然后 value[i] + step 或反之亦然。我知道这听起来很疯狂。想象一下 +1/-1 步的随机游走。像这样的序列:
0,1,2 将分配给 +1 类(也可以是 0,1,0,0,1,1,0,1,1,2) 0、-1、-2 将分配给类 -1(也可以是 0、-1、0、0、0、-1、-1、-1、-2) 0, + 1, 0, -1 or 0, -1, 0, 0, -1, 0, 1 等将是 0 类。我通过定义一个函数以“经典”(也许不是 Python 式)的方式解决了它:
import numpy as np
import pandas as pd
def FindClass(inarr, i=0, step=0.001, rr=2):
j = 0
foundClass = None
while i+j < len(inarr) - 1:
j += 1
if inarr[i+j] >= inarr[i] + step:
direction = 1
break
if inarr[i+j] <= inarr[i] - step:
direction = -1
break
while i+j < len(inarr)-1:
j += 1
if direction == 1 and inarr[i+j] >= inarr[i] + (step * rr):
foundClass = 1
break
elif direction == 1 and inarr[i+j] <= inarr[i] - step:
foundClass = 0
break
elif direction == -1 and inarr[i+j] <= inarr[i] - (step * rr):
foundClass = -1
break
elif direction == -1 and inarr[i+j] >= inarr[i] + step:
foundClass = 0
break
if foundClass is None:
foundClass = np.nan
return foundClass
然后对其进行迭代:
if __name__ == "__main__":
steps = np.random.randint(-1, 2, size= 10000)
randomwalk = steps.cumsum(0)
rc = pd.DataFrame('rw':randomwalk, 'result': np.nan)
for c in range(0, len(rc)-1):
rc.result[c] = FindClass(rc.rw, i=c, step=1)
print rc
在我的笔记本电脑(并运行 python 2.7)上,我得到了一个对于 10000 元素系列来说并不算“太”坏的分析:
python -m cProfile -s cumulative fbmk.py
<class 'pandas.core.frame.DataFrame'>
Int64Index: 10000 entries, 0 to 9999
Data columns (total 2 columns):
result 9996 non-null values
rw 10000 non-null values
dtypes: float64(1), int32(1)
932265 function calls (929764 primitive calls) in 2.643 seconds
Ordered by: cumulative time
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.106 0.106 2.646 2.646 fbmk.py:1(<module>)
9999 0.549 0.000 1.226 0.000 fbmk.py:4(FindClass)
158062 0.222 0.000 0.665 0.000 series.py:616(__getitem__)
2 0.029 0.014 0.561 0.281 __init__.py:3(<module>)
158062 0.226 0.000 0.443 0.000 index.py:718(get_value)
19998 0.070 0.000 0.442 0.000 frame.py:2082(__getattr__)
19998 0.111 0.000 0.331 0.000 frame.py:1986(__getitem__)
问题是:
是否有人认为可以在 pandas/numpy 中以提高性能的方式对该函数进行矢量化?
如果这件事在 R 中可以用更少的努力来实现,那也很好!
提前非常感谢!
【问题讨论】:
不是矢量化的,但也许你可以在cython中编写函数findClass
?
是的,当然这是可能的。这里的问题主要是因为这是一个逐行重复的任务,人们通常说对于 pandas 和类似的你必须“思考矢量”,避免循环......我试过了,但没有成功!
除了我在回答中的想法之外,我认为您可以通过重写函数以利用条件句获得显着的速度。您在 while 循环中放置了长条件,但您的逻辑允许您在大部分时间排除许多选项。这将导致执行的代码少得多,并且可能使您的执行时间缩短 2-4 倍。
也许shift函数对你有用,看看:pandas.pydata.org/pandas-docs/dev/generated/…
【参考方案1】:
根据您的问题的性质,您可以使用np.where
来查找跨越级别的位置并对时间序列进行分类。
这里最大的缺点是np.where
将为您提供时间序列高于value[i] + step
等的每个索引,这可能会将线性时间算法转变为二次时间算法。根据你将要处理的问题的大小,我希望你会在 prefactor 中收获很多;您甚至可能在二次时间 numpy 解决方案中领先。
从四处寻找,np.where
等价的“查找第一个索引”仍然是一个请求的功能。
【讨论】:
以上是关于向量化前瞻性函数 pandas 数据框的主要内容,如果未能解决你的问题,请参考以下文章