在 julia 中获得完整数据长度的指数移动平均值

问题描述 投票:0回答:2

我想使用 Python 中 pandas 库中提供的 ewma(指数加权移动平均)函数以及等效的 Julia 函数。在 Julia 中,有一个名为

MarketTechnicals.ema(m)
的函数可以计算 EMA 值。但是,此函数从大小为
m
的数据系列中的第
n
个元素开始计算值,因此结果数据的长度为
(n-m+1)
。虽然这是可以理解的,因为跨度是
m
,但 pandas ewma 函数从第一个元素开始计算,无论跨度长度是多少,如下所示:

#python
import pandas as pd
data = {"val": [1, 2, 3, 4, 5, 6]}
df = pd.DataFrame(data)
df['val'].ewm(m).mean()     
#output m=3
0    1.000000
1    1.571429
2    2.189189
3    2.851429
4    3.555698
5    4.299079

如果 df['val'] 的长度为 n,则此 Python 代码返回 n 个值。但以下 Julia 片段的长度将为 (n-m+1)

# julia
using DataFrames, MarketTechnicals
df = DataFrame(val = [1, 2, 3, 4, 5, 6])
ema(df.val,m)              
#output m=3
4×1 Matrix{Float64}:
 2.0
 3.0
 4.0
 5.0

我遇到了一个repo,它允许在 Julia 中使用 pandas 功能,但我不清楚语法,也无法在网上找到任何示例。

有人可以帮助我使用 pandas ewma 函数的 Julia 等效项吗?

pandas julia
2个回答
2
投票
  1. 根据 Dan 的评论,以下代码给出了预期结果:

    julia> ewma(w; m=3,a=m/(m+1)) = map!(
               i->i==1 ? w[1] :
               ((1-a)*w[i]+a*(1-a^(i-1))*r[i-1])/(1-a^i), (r = similar(w);),
               eachindex(w)
           )
    ewma (generic function with 1 method)
    
    julia> ewma(1.0:6.0; m=3)
    6-element Vector{Float64}:
     1.0
     1.5714285714285714
     2.189189189189189
     2.8514285714285714
     3.5556978233034573
     4.299079299079299
    
  2. 注意:以下代码的灵感来自于此博客中提出的方法。在下面的函数中,

    a
    是平滑系数:

    julia> function ewma(obs::Vector, a::Float64)
               T = length(obs)
               EWMA = Vector{Float64}(obs)
               for t∈2:T
                   EWMA[t] = a*obs[t]+(1-a)*EWMA[t-1]
               end
               EWMA
           end
    ewma (generic function with 1 method)
    
    julia> ewma([40, 45, 43, 31, 20], 0.3)
    5-element Vector{Float64}:
     40.0
     41.5
     41.949999999999996
     38.66499999999999
     33.06549999999999
    

1
投票

使用 pandas 源代码中的 pd.ewma 解释,我为 Julia 创建了以下函数。它满足

span, com, halflife, adjust, ignore
参数的选项

# julia code to recreate pandas.ewma
abstract type AlphaCalc end

struct Com{T<:Float64}<:AlphaCalc
  com::T
end

struct Span{T<:Float64}<:AlphaCalc
  span::T
end

struct Halflife{T<:Float64}<:AlphaCalc
  halflife::T
end

calcAlpha(val::Com)      = 1/(1 + val.com)
calcAlpha(val::Span)     = 2/(1 + val.span)
calcAlpha(val::Halflife) = 1 - exp(log(0.5)/val.halflife)

# julia code to recreate pandas.ewma
function ewma(
  data::AbstractVector,
  alphaMethod::AlphaCalc=Com(0.5);
  adjust::Bool=true,
  ignore_na::Bool=false
)

  alpha = calcAlpha(alphaMethod)
  n_samples = length(data)
  ewma_result = Vector{Float64}(undef, n_samples)

  if ignore_na
    ewma_result[1] = first(data)
    weights = [1.]

    for i in 2:n_samples
      if isnan(data[i])
        ewma_result[i] = ewma_result[i-1]
      else
        if !isnan(data[i-1])
          weights .*= (1 - alpha)
          push!(weights, 1)
        end
        # When adjust is True, use the weighted sum divided by the sum of weights
        if adjust
          weighted_sum = sum([weight * value for (weight, value) in zip(weights, data[1:i][.!isnan.(data[1:i])])])
          ewma_result[i] = weighted_sum / sum(weights)
        # When adjust is False, use the recursive formula
        else
          ewma_result[i] = (1 - alpha) * ewma_result[i-1] + alpha * data[i]
        end
      end
    end
  else
    ewma_result[1] = first(data)
    for i in 2:n_samples
      # When adjust is True, use the weighted sum divided by the sum of weights
      if adjust
        weights = [(1 - alpha) ^ (i - j - 1) for j in 0:(i-1)]
        weighted_sum = sum([weight * value for (weight, value) in zip(weights, data[1:i])])
        ewma_result[i] = weighted_sum / sum(weights)
      # When adjust is False, use the recursive formula
      else
        ewma_result[i] = (1 - alpha) * ewma_result[i-1] + alpha * data[i]
      end
    end
  end
  return ewma_result
end

它在朱莉娅身上进行了测试-

data = [1., 2., 3., 4., 5., 6., 8.0]
ewma_result = ewma(data, Com(5.), adjust=false, ignore_na=false);
println("EWMA result: ", ewma_result)
ewma_result = ewma(data, Span(5.), adjust=false, ignore_na=true);
println("EWMA result: ", ewma_result)
ewma_result = ewma(data, Halflife(5.), adjust=true, ignore_na=true);
println("EWMA result: ", ewma_result)

#outputs 
EWMA result: [1.0, 1.1666666666666667, 1.4722222222222223, 1.8935185185185186, 2.4112654320987654, 3.0093878600823047, 3.841156550068587]
EWMA result: [1.0, 1.3333333333333335, 1.888888888888889, 2.5925925925925926, 3.3950617283950617, 4.263374485596708, 5.508916323731139]
EWMA result: [1.0, 1.5346019613807635, 2.0921248294619423, 2.672350105842331, 3.2749760411274242, 3.8996216516650244, 4.754261118819774]

具有相应的Python功能-

>>> import pandas as pd
>>> data = [1., 2., 3., 4., 5., 6., 8.0]
>>> data = pd.Series(data)
>>> data.ewm(com=5.0, adjust=False, ignore_na=False).mean()
0    1.000000
1    1.166667
2    1.472222
3    1.893519
4    2.411265
5    3.009388
6    3.841157
dtype: float64
>>> data.ewm(span=5.0, adjust=False, ignore_na=True).mean()
0    1.000000
1    1.333333
2    1.888889
3    2.592593
4    3.395062
5    4.263374
6    5.508916
dtype: float64
>>> data.ewm(halflife=5.0, adjust=True, ignore_na=True).mean()
0    1.000000
1    1.534602
2    2.092125
3    2.672350
4    3.274976
5    3.899622
6    4.754261
dtype: float64
© www.soinside.com 2019 - 2024. All rights reserved.