Skip to content

Commit c9c3870

Browse files
Estimation statistics and prints (#57)
* add fit_stats method * add estimation results prints * change NelderMead to the default algorithm
1 parent eb90915 commit c9c3870

File tree

5 files changed

+119
-8
lines changed

5 files changed

+119
-8
lines changed

Project.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ version = "0.1.0"
77
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
88
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
99
Optim = "429524aa-4258-5aef-a3af-852621145aeb"
10+
Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7"
1011
SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b"
1112

1213
[compat]

examples/garch.jl

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,14 @@ gas = GAS(1, 1, Normal, 1.0, time_varying_params = [2])
5151
initial_point = [0.0; 0.5; 0.25; 0.75]
5252

5353
# Estimate the model
54-
f = fit(gas, y; initial_params = initial_params,
54+
f_ip_newton = fit(gas, y; initial_params = initial_params,
5555
opt_method = IPNewton(gas, [initial_point]; ub = ub, lb = lb))
5656

57+
estimation_stats_ip_newton = fit_stats(f_ip_newton)
58+
5759
# Another way to estimate the model is to rely on luck and give many random initial_points
5860
# for a non constrained optimization
59-
f = fit(gas, y; initial_params = initial_params,
60-
opt_method = NelderMead(gas, 100))
61+
f_nelder_mead = fit(gas, y; initial_params = initial_params,
62+
opt_method = NelderMead(gas, 100))
63+
64+
estimation_stats_nelder_mead = fit_stats(f_nelder_mead)

src/MLE.jl

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,60 @@
1-
export fit, fit!
1+
export fit, fit!, fit_stats
22

33
const DEFAULT_INITIAL_PARAM = NaN.*ones(1, 1)
44
const DEFAULT_NUM_SEEDS = 3
55
const DEFAULT_VERBOSE = 0
6+
const VARIANCE_ZERO = 1e-10
67

78
struct FittedSDM{T <: AbstractFloat}
9+
unknowns::UnknownsSDM
810
aic::T
911
bic::T
1012
llk::T
1113
coefs::Vector{T}
1214
numerical_hessian::Matrix{T}
1315
end
1416

17+
struct CoefsStatsSDM{T <: AbstractFloat}
18+
unknowns::UnknownsSDM
19+
coefs::Vector{T}
20+
std_errors::Vector{T}
21+
t_stat::Vector{T}
22+
p_values::Vector{T}
23+
end
24+
25+
struct EstimationStatsSDM{T <: AbstractFloat}
26+
loglikelihood::T
27+
aic::T
28+
bic::T
29+
np::T
30+
coefs_stats::CoefsStatsSDM{T}
31+
end
32+
33+
function fit_stats(f::FittedSDM{T}) where T
34+
estim_results = eval_coefs_stats(f)
35+
np = length(f.unknowns)
36+
return EstimationStatsSDM{T}(f.llk, f.aic, f.bic, np, estim_results)
37+
end
38+
39+
function eval_coefs_stats(f::FittedSDM{T}) where T
40+
np = length(f.unknowns)
41+
inv_H = inv(f.numerical_hessian)
42+
vars = diag(inv_H)
43+
for i in eachindex(vars)
44+
if vars[i] <= VARIANCE_ZERO
45+
vars[i] = VARIANCE_ZERO
46+
end
47+
end
48+
std_errors = sqrt.(vars)
49+
t_stats = f.coefs ./ std_errors
50+
51+
# Calculate p-values of the the t statistics
52+
t_dist = TDist(np)
53+
p_values = 1 .- 2*abs.(cdf.(t_dist, t_stats) .- 0.5)
54+
55+
return CoefsStatsSDM{T}(f.unknowns, f.coefs, std_errors, t_stats, p_values)
56+
end
57+
1558
mutable struct AuxEstimation{T <: AbstractFloat}
1659
psi::Vector{Vector{T}}
1760
numerical_hessian::Vector{Matrix{T}}
@@ -48,7 +91,7 @@ end
4891

4992
function fit(sdm::SDM{D, T}, y::Vector{T};
5093
initial_params::Matrix{T} = DEFAULT_INITIAL_PARAM,
51-
opt_method::AbstractOptimizationMethod = LBFGS(sdm, DEFAULT_NUM_SEEDS),
94+
opt_method::AbstractOptimizationMethod = NelderMead(sdm, DEFAULT_NUM_SEEDS),
5295
verbose::Int = DEFAULT_VERBOSE) where {D, T}
5396

5497
# Number of seed and number of params to estimate
@@ -96,7 +139,7 @@ function fit(sdm::SDM{D, T}, y::Vector{T};
96139
end
97140

98141
println("Finished!")
99-
return FittedSDM{T}(aic, bic, best_llk, coefs, num_hessian)
142+
return FittedSDM{T}(unknowns, aic, bic, best_llk, coefs, num_hessian)
100143
end
101144

102145
function fit!(sdm::SDM{D, T}, y::Vector{T};

src/ScoreDrivenModels.jl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
module ScoreDrivenModels
22

33
using Distributions, Optim, SpecialFunctions
4-
using LinearAlgebra
4+
using LinearAlgebra, Printf
55

6-
import Base.length, Base.deepcopy
6+
import Base: length, deepcopy, show
77

88
const SCALINGS = [0.0, 1/2, 1.0]
99
const BIG_NUM = 1e8
@@ -15,6 +15,7 @@ include("utils.jl")
1515
include("link_functions.jl")
1616
include("score.jl")
1717
include("MLE.jl")
18+
include("prints.jl")
1819

1920
# Optimization methods
2021
include("opt_methods/common_methods.jl")

src/prints.jl

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
function Base.show(io::IO, est::EstimationStatsSDM)
2+
println("--------------------------------------------------------")
3+
println("log-likelihood: ", @sprintf("%.4f", est.loglikelihood))
4+
println(" np: ", Int(est.np))
5+
println(" AIC: ", @sprintf("%.4f", est.aic))
6+
println(" BIC: ", @sprintf("%.4f", est.bic))
7+
print_coefs_stats(est.coefs_stats)
8+
return nothing
9+
end
10+
11+
function print_coefs_stats(coefs_stats)
12+
println("--------------------------------------------------------")
13+
println("Parameter Estimate Std.Error t stat p-value")
14+
offset = 1
15+
for i in coefs_stats.unknowns.ω
16+
p_c, p_std, p_t_stat, p_p_val = print_coefs_sta(coefs_stats, offset)
17+
p = build_print(p_c, p_std, p_t_stat, p_p_val, "ω_$i")
18+
println(p)
19+
offset += 1
20+
end
21+
for k in sort(collect(keys(coefs_stats.unknowns.A)))
22+
for i in coefs_stats.unknowns.A[k]
23+
p_c, p_std, p_t_stat, p_p_val = print_coefs_sta(coefs_stats, offset)
24+
ind = round(Int, sqrt(i))
25+
p = build_print(p_c, p_std, p_t_stat, p_p_val, "A_$(k)_$ind$ind")
26+
println(p)
27+
offset += 1
28+
end
29+
end
30+
for k in sort(collect(keys(coefs_stats.unknowns.B)))
31+
for i in coefs_stats.unknowns.B[k]
32+
p_c, p_std, p_t_stat, p_p_val = print_coefs_sta(coefs_stats, offset)
33+
ind = round(Int, sqrt(i))
34+
p = build_print(p_c, p_std, p_t_stat, p_p_val, "B_$(k)_$ind$ind")
35+
println(p)
36+
offset += 1
37+
end
38+
end
39+
return nothing
40+
end
41+
42+
function print_coefs_sta(sta, offset::Int)
43+
p_c = @sprintf("%.4f", sta.coefs[offset])
44+
p_std = @sprintf("%.4f", sta.std_errors[offset])
45+
p_t_stat = @sprintf("%.4f", sta.t_stat[offset])
46+
p_p_val = @sprintf("%.4f", sta.p_values[offset])
47+
return p_c, p_std, p_t_stat, p_p_val
48+
end
49+
50+
function build_print(p_c, p_std, p_t_stat, p_p_val, param)
51+
p = ""
52+
p *= param
53+
p *= " "^max(0, 23 - length(p_c) - length(param))
54+
p *= p_c
55+
p *= " "^max(0, 12 - length(p_std))
56+
p *= p_std
57+
p *= " "^max(0, 11 - length(p_t_stat))
58+
p *= p_t_stat
59+
p *= " "^max(0, 10 - length(p_p_val))
60+
p *= p_p_val
61+
return p
62+
end

0 commit comments

Comments
 (0)