From 4e03d3396849cdc64e5ec787e0b28806a08283cd Mon Sep 17 00:00:00 2001 From: Dongdong Kong Date: Mon, 24 Jul 2023 10:31:05 +0800 Subject: [PATCH] add slope_mk and slope_p --- ext/IpaperSlopeExt/IpaperSlopeExt.jl | 6 ++-- ext/IpaperSlopeExt/mktrend.jl | 43 ++++++++++++------------- ext/IpaperSlopeExt/slope_fun.jl | 48 ++++++++++++++++++++++++++++ src/Slope/Slope.jl | 7 ++-- test/runtests.jl | 3 +- test/test-slope.jl | 12 +++++++ 6 files changed, 91 insertions(+), 28 deletions(-) create mode 100644 ext/IpaperSlopeExt/slope_fun.jl create mode 100644 test/test-slope.jl diff --git a/ext/IpaperSlopeExt/IpaperSlopeExt.jl b/ext/IpaperSlopeExt/IpaperSlopeExt.jl index b358531..75975f1 100644 --- a/ext/IpaperSlopeExt/IpaperSlopeExt.jl +++ b/ext/IpaperSlopeExt/IpaperSlopeExt.jl @@ -7,9 +7,9 @@ using StatsBase: autocor, tiedrank using Distributions: ccdf, Normal using Ipaper -using Ipaper: lm_resid -# , trend_mk +using Ipaper: lm_resid, slope_mk, slope_p, mkTrend -include("mktrend.jl") +include("mkTrend.jl") +include("slope_fun.jl") end diff --git a/ext/IpaperSlopeExt/mktrend.jl b/ext/IpaperSlopeExt/mktrend.jl index 8fee8e7..943ac4b 100644 --- a/ext/IpaperSlopeExt/mktrend.jl +++ b/ext/IpaperSlopeExt/mktrend.jl @@ -1,3 +1,17 @@ +function _slope_sen(y::AbstractVector, x::AbstractVector=1:length(y)) + n = length(x) + V = fill(NaN, Int((n^2 - n) / 2)) + k = 0 + for i in 2:n + for j in 1:(i-1) + k += 1 + V[k] = (y[i] - y[j]) / (x[i] - x[j]) + end + end + median(V) +end + + """ trend_mk(y::AbstractVector{T}; ci=0.95) where {T<:Real} @@ -6,7 +20,7 @@ - `y`: numeric vector - `x`: (optional) numeric vector - `ci`: critical value of autocorrelation - + # Return - `Z0` : The original (non corrected) Mann-Kendall test Z statistic. @@ -33,12 +47,11 @@ # Example ```julia -julia> x = [4.81, 4.17, 4.41, 3.59, 5.87, 3.83, 6.03, 4.89, 4.32, 4.69]; -julia> trend_mk(x) +julia> mkTrend([4.81, 4.17, 4.41, 3.59, 5.87, 3.83, 6.03, 4.89, 4.32, 4.69]) (z0 = 0.35777087639996635, pval0 = 0.7205147871362552, z = 0.35777087639996635, pval = 0.7205147871362552, slope = 0.040000000000000036, intercept = 4.441) ``` """ -function Ipaper.trend_mk(y::AbstractVector{T}; ci=0.95) where {T<:Real} +function Ipaper.mkTrend(y::AbstractVector, x::AbstractVector; ci=0.95) z0 = z = pval0 = pval = slp = intercept = NaN # y = dropmissing(y) @@ -92,27 +105,13 @@ function Ipaper.trend_mk(y::AbstractVector{T}; ci=0.95) where {T<:Real} z0 = (S + 1) / sqrt(var_S) end - pval = 2 * ccdf(Normal(), abs(z)) - pval0 = 2 * ccdf(Normal(), abs(z0)) + pvalue = 2 * ccdf(Normal(), abs(z)) + pvalue0 = 2 * ccdf(Normal(), abs(z0)) # Tau = S / (0.5 * n * (n - 1)) - slope = slope_sen(y) + slope = _slope_sen(y, x) intercept = mean(y .- slope .* (1:n)) - (; z0, pval0, z, pval, slope, intercept) -end - - -function slope_sen(y::AbstractVector{T}, x=1:length(y)) where {T<:Real} - n = length(x) - V = fill(NaN, Int((n^2 - n) / 2)) - k = 0 - for i in 2:n - for j in 1:(i-1) - k += 1 - V[k] = (y[i] - y[j]) / (x[i] - x[j]) - end - end - median(V) + (; z0, pvalue0, z, pvalue, slope, intercept) end # export trend_mk diff --git a/ext/IpaperSlopeExt/slope_fun.jl b/ext/IpaperSlopeExt/slope_fun.jl new file mode 100644 index 0000000..bc2ee35 --- /dev/null +++ b/ext/IpaperSlopeExt/slope_fun.jl @@ -0,0 +1,48 @@ +using Distributions: TDist, cdf +using StatsBase: cov, var + + +function pt(x::Float64, df::Int) + t = TDist(df) + cdf(t, x) +end + + +""" + slope_p(y::AbstractVector, x::AbstractVector=1:length(y)) + +# Reference +1. https://zhuanlan.zhihu.com/p/642186978 + +# Example +```julia +x = [1, 2, 3, 4, 5]; +y = [2, 4, 5, 4, 6]; +slope_p(y) +``` +""" +function Ipaper.slope_p(y::AbstractVector, x::AbstractVector=1:length(y); ignored...) + n = length(x) + df = n - 2 + + covxy = cov(x, y) + varx = var(x) # (x - mean(x))' * (x - mean(x)) / (n - 1) + slope = covxy / varx + resid = lm_resid(y, x) + + _var = sum((x .- mean(x)) .^ 2) + resvar = sum(resid .^ 2) / df + + se = sqrt(resvar / _var) + tval = slope / se + pvalue = 2 * (1 - pt(abs(tval), df)) + + # (; slope, se, tval, pvalue) + (; slope, pvalue) #, sd = se +end + + +function Ipaper.slope_mk(y::AbstractVector, x::AbstractVector=1:length(y); ci=0.95, ignored...) + r = mkTrend(y, x; ci) + (;slope = r.slope, pvalue = r.pvalue) +end diff --git a/src/Slope/Slope.jl b/src/Slope/Slope.jl index 1bc4d26..7986438 100644 --- a/src/Slope/Slope.jl +++ b/src/Slope/Slope.jl @@ -2,7 +2,10 @@ include("base.jl") include("linreg.jl") # include("mktrend.jl") -function trend_mk end +function mkTrend end +function slope_mk end +function slope_p end -export trend_mk +export mkTrend, + slope_mk, slope_p diff --git a/test/runtests.jl b/test/runtests.jl index e4b52fd..47e29aa 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -24,4 +24,5 @@ include("test-stat_movmean.jl") include("test-stat_anomaly.jl") include("test-stat_threshold.jl") include("test-stat_warmingLevel.jl") -# end + +include("test-slope.jl") diff --git a/test/test-slope.jl b/test/test-slope.jl new file mode 100644 index 0000000..cc55a69 --- /dev/null +++ b/test/test-slope.jl @@ -0,0 +1,12 @@ +using Distributions +using Ipaper +using Test + +@testset "slope_fun" begin + x = [4.81, 4.17, 4.41, 3.59, 5.87, 3.83, 6.03, 4.89, 4.32, 4.69] + t_mk = slope_mk(x) + t_lm = slope_p(x) + + @test t_mk == (slope=0.040000000000000036, pvalue=0.7205147871362552) + @test t_lm == (slope=0.04636363636363642, pvalue=0.6249862523021623) +end