我想使用 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 等效项吗?
根据 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
注意:以下代码的灵感来自于此博客中提出的方法。在下面的函数中,
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
使用 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