Python 使用需要先前计算值的numpy对值进行矢量化计算
我试图从Investopedia计算EMA的一个特殊公式,它看起来像Python 使用需要先前计算值的numpy对值进行矢量化计算,python,numpy,vectorization,Python,Numpy,Vectorization,我试图从Investopedia计算EMA的一个特殊公式,它看起来像 EmaToday = (ValueToday ∗ (Smoothing / 1+Days)) + (EmaYesterday * (1 - (Smoothing / 1+Days))) 我们可以将其简化为: Smoothing and Days are constants. Let's call (Smoothing / 1 + Days) as 'M' The simplified equatio
EmaToday = (ValueToday ∗ (Smoothing / 1+Days))
+ (EmaYesterday * (1 - (Smoothing / 1+Days)))
我们可以将其简化为:
Smoothing and Days are constants.
Let's call (Smoothing / 1 + Days) as 'M'
The simplified equation becomes:
EmaToday = ((ValueToday - EmaYesterday) * M) + EmaYesterday
我们可以在传统python中使用循环来实现这一点,如下所示:
# Initialize an empty numpy array to hold calculated ema values
emaTodayArray = np.zeros((1, valueTodayArray.size - Days), dtype=np.float32)
ema = emaYesterday
# Calculate ema
for i, valueToday in enumerate(np.nditer(valueList)):
ema = ((valueToday - ema) * M) + ema
emaTodayArray[i] = ema
emaTodayArray
保存所有计算的EMA值
我很难弄清楚如何将其完全矢量化,因为每次新的计算都需要emaday
值
如果首先可以使用numpy实现完全矢量化,如果有人能给我指路,我会非常感激
注意:为了让你的代码运行,我必须填写一些假人,请检查它们是否正常 可以通过变换
ema[i]~>ema'[i]=ema[i]x(1-M)^-i
对循环进行矢量化,然后它就变成了一个cumsum
这在下面实现为ema\u pp\u naive
此方法的问题是,对于中等大小的i
(~10^3),1-M^-i项可能溢出,导致结果无效
我们可以通过使用log空间(使用np.logaddexp
求和)来绕过这个问题。这个ema\u pp\u safe
比简单的方法要贵很多,但仍然比原始循环快10倍以上。在我快速而肮脏的测试中,这给出了一百万个术语及更多术语的正确结果
代码:
运行示例:
K = 100
naive method correct: True
safe method correct: True
OP 0.236 ms naive 0.061 ms safe 0.053 ms
K = 1000
naive method correct: False
safe method correct: True
OP 2.397 ms naive 0.224 ms safe 0.183 ms
K = 1000000
naive method correct: False
safe method correct: True
OP 2145.956 ms naive 18.342 ms safe 108.528 ms
首先,我认为您不需要
nditer
来进行迭代;它对速度没有帮助(如果这就是你使用它的原因)。如果您确实使用它,那么就有一种方法可以获取索引和值,因此您不必使用枚举
;一个值取决于前一个值。大多数快速编译的numpy
操作本质上是并行的——至少从Python的角度来看是如此——所有值都是一次计算出来的。(底层C代码实际上是迭代的)。我们最接近串行操作的是ufuncs
的accumulate
方法,其中cumsum
是最常见的。@hpaulj所以本质上你的意思是,一旦我修复了循环的nditer部分,就这个计算而言,就没有什么可以做的了?这太棒了。把它标对了。我花了一些时间想明白,当我把它分解并解决时,你是如何想出这个天真的版本的。非常感谢你。如果您能更详细地介绍一下您是如何处理它的,并在每一步分解您的逻辑(即使是日志版本),我将不胜感激。再次感谢您抽出时间来帮助我!:)@首先,阿披实克马尼亚尔再看一看hpaulj的评论。累积一个内置的ufunc
实际上或多或少是对顺序操作进行矢量化的唯一方法(cumsum
本质上是add.accumulate
)。发现ema
能够扩展累积的总和是一个经验问题。至于log
版本,从概念上讲,它实际上只不过是简单版本的log
。我们得到的结果是,(1-M)^-i很容易溢出,现在只是非常易于管理的-ix日志(1-M)。棘手的一点是,实际上“一个人不能拿”一笔金额的记录。。。。。。(或cumsum)在某种意义上说,没有封闭的公式,但幸运的是,有np.logaddexp
从术语的日志中计算总和的日志。实际上,它确实需要exp,添加并再次获取日志,但是要以一种安全的方式防止溢出。非常感谢所有的帮助和见解!
K = 100
naive method correct: True
safe method correct: True
OP 0.236 ms naive 0.061 ms safe 0.053 ms
K = 1000
naive method correct: False
safe method correct: True
OP 2.397 ms naive 0.224 ms safe 0.183 ms
K = 1000000
naive method correct: False
safe method correct: True
OP 2145.956 ms naive 18.342 ms safe 108.528 ms