Python 使用需要先前计算值的numpy对值进行矢量化计算

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

我试图从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 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