Skip to content

Commit ceedd74

Browse files
Viz backtest (#130)
* Add backtest recipes * update main file and tests * Update scripts
1 parent 4456d6b commit ceedd74

File tree

8 files changed

+55
-12
lines changed

8 files changed

+55
-12
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "ScoreDrivenModels"
22
uuid = "4a87933e-d659-11e9-0e65-7f40dedd4a3a"
33
authors = ["guilhermebodin <[email protected]>, raphaelsaavedra <[email protected]>"]
4-
version = "0.1.7"
4+
version = "0.1.8"
55

66
[deps]
77
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"

examples/ane.jl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ y_test = y[401:460]
99
# Set RNG seed to guarantee consistent results
1010
Random.seed!(123)
1111

12-
# Specify GAS model: a lognormal model with time-varying μ, constant σ, and lags 1 and 12
13-
gas = Model([1, 2, 11, 12], [1, 2, 11, 12], LogNormal, 0.0; time_varying_params=[1])
12+
# Specify GAS model: a lognormal model with time-varying μ, constant σ, and lags 4 and 12
13+
gas = Model(4, 12, LogNormal, 1.0; time_varying_params=[1])
1414

1515
# Obtain initial parameters to start the GAS recursion
1616
initial_params = dynamic_initial_params(y_train, gas)
@@ -20,6 +20,7 @@ f = ScoreDrivenModels.fit!(gas, y_train; initial_params=initial_params)
2020

2121
# Print estimation statistics
2222
results(f)
23+
plot(f)
2324

2425
# Simulate 1000 future scenarios and obtain the 5% and 95% quantiles in each time period
2526
forec = forecast(y_train, gas, 60; S=1000, initial_params=initial_params)

examples/cpichg.jl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ f = fit!(gas, y; opt_method=LBFGS(gas, 5))
2828

2929
# Print estimation statistics
3030
results(f)
31+
plot(f)
3132

3233
# Perform forecast via simulations for 12 time periods ahead
3334
forec = forecast(y, gas, 12)
@@ -37,3 +38,11 @@ forec.parameter_forecast
3738

3839
# Similarly, we can access the simulated observation scenarios
3940
forec.observation_scenarios
41+
42+
gas_t = Model(1, 1, TDistLocationScale, 0.0; time_varying_params = [1])
43+
steps_ahead = 50
44+
first_idx = 150
45+
b_t = backtest(gas_t, y, steps_ahead, first_idx)
46+
plot(b_t, "GAS(1, 1) Student t")
47+
using Plots
48+
plot!(b_t, "GAS(1, 1) Student t")

src/ScoreDrivenModels.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,5 +47,6 @@ include("distributions/weibull.jl")
4747

4848
include("visualization/forecast.jl")
4949
include("visualization/residuals.jl")
50+
include("visualization/backtest.jl")
5051

5152
end

src/backtest.jl

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,15 @@ export backtest
22

33
struct Backtest
44
abs_errors::Matrix{Float64}
5+
mae::Vector{Float64}
56
crps_scores::Matrix{Float64}
7+
mean_crps::Vector{Float64}
68
function Backtest(n::Int, steps_ahead::Int)
7-
abs_errors = Matrix{Float64}(undef, n, steps_ahead)
8-
crps_scores = Matrix{Float64}(undef, n, steps_ahead)
9-
return new(abs_errors, crps_scores)
9+
abs_errors = Matrix{Float64}(undef, steps_ahead, n)
10+
crps_scores = Matrix{Float64}(undef, steps_ahead, n)
11+
mae = Vector{Float64}(undef, steps_ahead)
12+
mean_crps = Vector{Float64}(undef, steps_ahead)
13+
return new(abs_errors, mae, crps_scores, mean_crps)
1014
end
1115
end
1216

@@ -36,8 +40,8 @@ TODO
3640
"""
3741
function backtest(gas::Model{<:Distribution, T}, y::Vector{T}, steps_ahead::Int, start_idx::Int;
3842
S::Int = 10_000,
39-
initial_params = stationary_initial_params(gas),
40-
opt_method = NelderMead(gas, 3)) where T
43+
initial_params::Matrix{T} = stationary_initial_params(gas),
44+
opt_method = NelderMead(gas, DEFAULT_NUM_SEEDS)) where T
4145
num_mle = length(y) - start_idx - steps_ahead
4246
b = Backtest(num_mle, steps_ahead)
4347
for i in 1:num_mle
@@ -49,8 +53,12 @@ function backtest(gas::Model{<:Distribution, T}, y::Vector{T}, steps_ahead::Int,
4953
forec = forecast(y_to_fit, gas_to_fit, steps_ahead; S=S, initial_params=initial_params)
5054
abs_errors = evaluate_abs_error(y_to_verify, forec.observation_forecast)
5155
crps_scores = evaluate_crps(y_to_verify, forec.observation_scenarios)
52-
b.abs_errors[i, :] = abs_errors
53-
b.crps_scores[i, :] = crps_scores
56+
b.abs_errors[:, i] = abs_errors
57+
b.crps_scores[:, i] = crps_scores
58+
end
59+
for i in 1:steps_ahead
60+
b.mae[i] = mean(b.abs_errors[i, :])
61+
b.mean_crps[i] = mean(b.crps_scores[i, :])
5462
end
5563
return b
5664
end

src/visualization/backtest.jl

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
RecipesBase.@recipe function f(b::ScoreDrivenModels.Backtest, name::String)
2+
xguide := "lead times"
3+
@series begin
4+
seriestype := :path
5+
label := "MAE " * name
6+
marker := :circle
7+
b.mae
8+
end
9+
@series begin
10+
seriestype := :path
11+
label := "Mean CRPS " * name
12+
marker := :circle
13+
b.mean_crps
14+
end
15+
end

src/visualization/residuals.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
RecipesBase.@recipe function f(fi::ScoreDrivenModels.Fitted)
1+
RecipesBase.@recipe function f(fi::Fitted)
22
layout := (2, 2)
33
acf = autocor(fi.pearson_residuals)[2:end]
44
@series begin
55
seriestype := :path
66
label := ""
77
seriescolor := "black"
88
subplot := 1
9+
marker := :circle
910
fi.pearson_residuals
1011
end
1112
@series begin

test/test_visualization.jl

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
@testset "Visualization Residuals" begin
1+
@testset "Visualizations" begin
22
ω = [0.1, 0.1]
33
A = [0.5 0; 0 0.5]
44
B = [0.5 0; 0 0.5]
@@ -8,4 +8,12 @@
88
f = fit!(gas, simulation; verbose = 2, opt_method = ScoreDrivenModels.LBFGS(gas, 3))
99
rec = RecipesBase.apply_recipe(Dict{Symbol, Any}(), f)
1010
@test length(rec) == 7
11+
ω = [0.1, 0.1]
12+
A = [0.5 0; 0 0.5]
13+
B = [0.5 0; 0 0.5]
14+
simulation = simulate_GAS_1_1(Normal, 0.0, ω, A, B, 1)
15+
gas = ScoreDrivenModels.Model(1, 1, Normal, 0.0)
16+
bac = backtest(gas, simulation, 10, 4985)
17+
rec = RecipesBase.apply_recipe(Dict{Symbol, Any}(), bac, "name")
18+
@test length(rec) == 2
1119
end

0 commit comments

Comments
 (0)