diff --git a/Project.toml b/Project.toml index 9742925..bbd4145 100644 --- a/Project.toml +++ b/Project.toml @@ -24,6 +24,7 @@ Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" StatsAPI = "82ae8749-77ed-4fe6-ae5f-f523153014b0" StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91" +StatsModels = "3eaba693-59b7-5ba5-a881-562e759f1c8d" Vcov = "ec2bfdc2-55df-4fc9-b9ae-4958c2cf2486" [compat] diff --git a/examples/example_ols_2step.jl b/examples/example_ols_2step.jl index 47bba1c..b4b3d97 100644 --- a/examples/example_ols_2step.jl +++ b/examples/example_ols_2step.jl @@ -57,16 +57,36 @@ myopts = GMMTools.GMMOptions( trace=1) # estimate model -myfit = fit(df, ols_moments_fn, theta0, mode=:twostep, opts=myopts) +myfit = GMMTools.fit(df, ols_moments_fn, theta0, mode=:twostep, opts=myopts) # compute asymptotic variance-covariance matrix and save in myfit.vcov vcov_simple(df, ols_moments_fn, myfit) # print table with results + + # temp = GMMTools.GMMModel(myfit) + # dfsdfsdf + # RegressionTables.get_coefname() + # # formula_schema + # formula(temp) + + temp = GMMTools.GMMModel(myfit) + formula(temp) + display(temp) + + dsfd + # RegressionTables.formula(m::GMMModel) = term(m.responsename) ~ sum(term.(String.(m.coefnames))) + GMMTools.regtable(myfit) +fsdfds + f1 = term("mpg") ~ term("acceleration") + term("acceleration2") + get_coefname(f1.rhs) + + +sdf diff --git a/examples/temp/step1/Wstep2.csv b/examples/temp/step1/Wstep2.csv index 152d218..505c3b2 100644 --- a/examples/temp/step1/Wstep2.csv +++ b/examples/temp/step1/Wstep2.csv @@ -1,2 +1,2 @@ -0.716038140204011,-0.04348751629684115 --0.04348751629684115,0.00271677294881702 +0.7160381402040145,-0.043487516296841375 +-0.043487516296841375,0.0027167729488170337 diff --git a/examples/temp/step1/results.csv b/examples/temp/step1/results.csv index 6b90ba6..6d66f7e 100644 --- a/examples/temp/step1/results.csv +++ b/examples/temp/step1/results.csv @@ -1,21 +1,21 @@ idx,obj_value,converged,iterations,iteration_limit_reached,time_it_took,theta_hat,theta0,is_optimum -1,1.0090134771009219e-23,true,3,false,3.5336567,"[4.969793004358799, 1.1912045293436935]","[0.03833248646601629, 0.213845359778582]",0 -2,1.7558726393742873e-23,true,3,false,0.0002598,"[4.969793004392259, 1.1912045293416091]","[-0.7042838077754542, -0.4007992090593657]",0 -3,3.485090023460716e-24,true,3,false,0.0002258,"[4.9697930043155, 1.1912045293463907]","[1.4214984593810815, -0.5777261953257666]",0 -4,1.709405940914258e-23,true,3,false,0.0001495,"[4.969793004390416, 1.191204529341724]","[-0.4658959078249555, -0.7303008298610437]",0 -5,2.7773874886452683e-24,true,4,false,0.0002099,"[4.969793004308891, 1.1912045293468023]","[-1.365080912437378, -1.3208174975844296]",0 -6,6.909694086715038e-24,true,3,false,0.0002126,"[4.969793004340717, 1.19120452934482]","[0.5431992343373382, 0.09271546518564394]",0 -7,1.0369010653532012e-23,true,3,false,0.0001562,"[4.969793004360255, 1.1912045293436029]","[-0.7590535993444354, 0.9209639329677229]",0 -8,5.088050807273377e-27,true,4,false,0.0002343,"[4.969793004256079, 1.1912045293500921]","[0.745620993889791, -2.216096423049429]",1 -9,5.7608307585384585e-24,true,3,false,0.0005141,"[4.969793004333189, 1.1912045293452889]","[0.8442354651341021, -0.3265277272261217]",0 -10,1.1371844801828514e-23,true,3,false,0.000318,"[4.969793004365242, 1.1912045293432922]","[-1.0120757369891493, 1.1470306234136702]",0 -11,7.622488159174278e-24,true,3,false,0.000372,"[4.969793004345065, 1.191204529344549]","[0.7232770971838263, -0.728534008508048]",0 -12,2.729599738585982e-24,true,3,false,0.0003055,"[4.96979300430846, 1.1912045293468292]","[0.5202990342876057, 1.1204520037446837]",0 -13,1.1443429254297673e-25,true,3,false,0.0003278,"[4.969793004265068, 1.1912045293495324]","[1.6996228215478644, 1.0844860147154771]",0 -14,1.0212181766944047e-26,true,4,false,0.0003378,"[4.969793004257214, 1.1912045293500215]","[-1.0989445324831357, -0.0993402202293609]",0 -15,2.4923787040363005e-24,true,3,false,0.000244,"[4.96979300430602, 1.1912045293469813]","[1.5447563259135333, -0.22651795438142638]",0 -16,4.8183300124265374e-24,true,3,false,0.0002471,"[4.969793004326375, 1.1912045293457134]","[1.7376928272513674, -1.2953938355637125]",0 -17,1.7932649305832416e-24,true,4,false,0.0003495,"[4.969793004298091, 1.1912045293474751]","[-1.3972500397371668, -1.1529219835943225]",0 -18,1.4139785609879107e-23,true,3,false,0.0002761,"[4.969793004378028, 1.1912045293424958]","[-0.27322961221704645, -0.5101173409267433]",0 -19,1.732439662937055e-26,true,4,false,0.0003514,"[4.969793004258192, 1.1912045293499605]","[-1.7983567634893314, 0.8231200506166791]",0 -20,1.6558411471442423e-23,true,3,false,0.0005128,"[4.969793004388284, 1.191204529341857]","[-0.6634712267123949, -0.2399591176621829]",0 +1,6.008047737764278e-24,true,3,false,5.5143167,"[4.969793004334855, 1.1912045293451852]","[0.7333549537269617, -0.08702752778732076]",0 +2,1.0557870385606695e-23,true,3,false,0.0003319,"[4.969793004361183, 1.1912045293435451]","[0.3348882897775347, -0.7803017039276787]",0 +3,2.127064708754081e-24,true,3,false,0.0003428,"[4.9697930043020655, 1.1912045293472275]","[1.4969905819055915, 0.35078506512446334]",0 +4,5.678514061361174e-27,true,3,false,0.0002609,"[4.9697930042562595, 1.191204529350081]","[1.9104529355027664, 1.3598422250610078]",1 +5,4.821438071086582e-24,true,3,false,0.0002897,"[4.969793004326411, 1.191204529345711]","[0.9728232798844213, -0.14067410011660123]",0 +6,7.813903509746564e-24,true,3,false,0.0003732,"[4.969793004346201, 1.1912045293444784]","[-0.4584614418357323, 1.0411399628260511]",0 +7,1.3648352663569037e-23,true,3,false,0.0003689,"[4.969793004375888, 1.191204529342629]","[0.9174389714694687, -1.5084014988779522]",0 +8,1.0390507291325953e-23,true,3,false,0.0003546,"[4.969793004360332, 1.191204529343598]","[0.12249553087948825, -0.3423467875721143]",0 +9,9.437838946189772e-25,true,4,false,0.0005973,"[4.969793004285966, 1.1912045293482305]","[-0.9204024669915305, -1.2627650563754986]",0 +10,2.298844392076946e-25,true,4,false,0.0007173,"[4.969793004269693, 1.1912045293492444]","[-1.425317850889396, -0.13188760801442104]",0 +11,1.2036885185904109e-23,true,3,false,0.0006497,"[4.969793004368461, 1.1912045293430917]","[-0.15268667522019008, -0.17239262787204485]",0 +12,1.7481638769830322e-24,true,3,false,0.0007074,"[4.969793004297571, 1.1912045293475075]","[1.3023574705316272, 0.5077729828299388]",0 +13,4.069665898792638e-24,true,3,false,0.008444,"[4.969793004320511, 1.1912045293460785]","[0.15426908206241488, 1.5402712760936221]",0 +14,1.8133175621256172e-23,true,3,false,0.0003636,"[4.969793004394511, 1.191204529341469]","[-1.7267252812920018, 1.0219210821259985]",0 +15,8.52026540787376e-24,true,3,false,0.0003829,"[4.969793004350281, 1.1912045293442242]","[0.2747757058146626, 0.1720449857423505]",0 +16,4.67837413012653e-24,true,3,false,0.0004382,"[4.969793004325323, 1.191204529345779]","[1.0110359111683276, -0.17639294266435857]",0 +17,1.531655549498546e-24,true,4,false,0.0007845,"[4.969793004294775, 1.1912045293476818]","[-2.136663990166246, -0.006788132262980114]",0 +18,3.1420837462174614e-26,true,4,false,0.0008888,"[4.969793004259756, 1.1912045293498632]","[-1.2334796855846475, 0.23491144426446822]",0 +19,1.3659190164525006e-23,true,3,false,0.000863,"[4.969793004375919, 1.191204529342627]","[-0.2143326300938984, -0.5149354181924408]",0 +20,8.313046066730828e-24,true,3,false,0.0004578,"[4.969793004349079, 1.191204529344299]","[-0.6336756499029971, 1.4154829458615907]",0 diff --git a/examples/temp/step2/results.csv b/examples/temp/step2/results.csv index 0188a5c..a2a1a4e 100644 --- a/examples/temp/step2/results.csv +++ b/examples/temp/step2/results.csv @@ -1,21 +1,21 @@ idx,obj_value,converged,iterations,iteration_limit_reached,time_it_took,theta_hat,theta0,is_optimum -1,2.6104875942959174e-30,true,3,false,3.4166789,"[4.969793004253967, 1.1912045293502238]","[0.03833248646601629, 0.213845359778582]",0 -2,1.4614007105013917e-30,true,3,false,0.0002614,"[4.9697930042539635, 1.191204529350224]","[-0.7042838077754542, -0.4007992090593657]",0 -3,1.4614007105013917e-30,true,3,false,0.0002229,"[4.9697930042539635, 1.191204529350224]","[1.4214984593810815, -0.5777261953257666]",0 -4,2.1743011519099462e-30,true,3,false,0.0002113,"[4.969793004253983, 1.1912045293502227]","[-0.4658959078249555, -0.7303008298610437]",0 -5,4.503755737267253e-31,true,4,false,0.0002083,"[4.969793004253949, 1.191204529350225]","[-1.365080912437378, -1.3208174975844296]",0 -6,3.6860454164630275e-31,true,3,false,0.0001864,"[4.96979300425393, 1.1912045293502262]","[0.5431992343373382, 0.09271546518564394]",0 -7,3.017625637198401e-31,true,3,false,0.000243,"[4.969793004253935, 1.1912045293502258]","[-0.7590535993444354, 0.9209639329677229]",0 -8,2.4187576534063886e-31,true,4,false,0.0191076,"[4.969793004253909, 1.1912045293502274]","[0.745620993889791, -2.216096423049429]",0 -9,5.549664479705941e-31,true,3,false,0.0003322,"[4.969793004253944, 1.1912045293502254]","[0.8442354651341021, -0.3265277272261217]",0 -10,1.6492852457751382e-30,true,3,false,0.0002759,"[4.96979300425396, 1.1912045293502243]","[-1.0120757369891493, 1.1470306234136702]",0 -11,1.0024279650486883e-30,true,3,false,0.0002529,"[4.969793004253946, 1.1912045293502251]","[0.7232770971838263, -0.728534008508048]",0 -12,9.987757014848227e-31,true,3,false,0.00028,"[4.9697930042539396, 1.1912045293502256]","[0.5202990342876057, 1.1204520037446837]",0 -13,2.4187576534063886e-31,true,3,false,0.0002269,"[4.969793004253909, 1.1912045293502274]","[1.6996228215478644, 1.0844860147154771]",0 -14,2.3803135524615715e-32,true,4,false,0.0003642,"[4.969793004253907, 1.1912045293502276]","[-1.0989445324831357, -0.0993402202293609]",1 -15,1.0024279650486883e-30,true,3,false,0.0003356,"[4.969793004253946, 1.1912045293502251]","[1.5447563259135333, -0.22651795438142638]",0 -16,1.2764725426287234e-30,true,3,false,0.0003944,"[4.969793004253947, 1.1912045293502251]","[1.7376928272513674, -1.2953938355637125]",0 -17,4.299320562841262e-30,true,4,false,0.0003926,"[4.969793004253975, 1.1912045293502234]","[-1.3972500397371668, -1.1529219835943225]",0 -18,4.5866524809437025e-30,true,3,false,0.0004796,"[4.969793004253978, 1.1912045293502231]","[-0.27322961221704645, -0.5101173409267433]",0 -19,1.4564838996979999e-30,true,4,false,0.0003656,"[4.969793004253953, 1.1912045293502247]","[-1.7983567634893314, 0.8231200506166791]",0 -20,2.1766270139140864e-30,true,3,false,0.0004111,"[4.969793004253967, 1.191204529350224]","[-0.6634712267123949, -0.2399591176621829]",0 +1,2.6104875942959304e-30,true,3,false,5.4577173,"[4.969793004253967, 1.1912045293502238]","[0.7333549537269617, -0.08702752778732076]",0 +2,4.590800393903285e-30,true,3,false,0.0003906,"[4.969793004254001, 1.1912045293502218]","[0.3348882897775347, -0.7803017039276787]",0 +3,1.0024279650486932e-30,true,3,false,0.0003002,"[4.969793004253946, 1.1912045293502251]","[1.4969905819055915, 0.35078506512446334]",0 +4,3.6860454164630258e-31,true,3,false,0.0002825,"[4.96979300425393, 1.1912045293502262]","[1.9104529355027664, 1.3598422250610078]",0 +5,5.549664479705953e-31,true,3,false,0.0003598,"[4.969793004253943, 1.1912045293502254]","[0.9728232798844213, -0.14067410011660123]",0 +6,1.4614007105013984e-30,true,3,false,0.0004908,"[4.9697930042539635, 1.191204529350224]","[-0.4584614418357323, 1.0411399628260511]",0 +7,1.1980422091934478e-30,true,3,false,0.0004401,"[4.969793004253957, 1.1912045293502245]","[0.9174389714694687, -1.5084014988779522]",0 +8,3.1674241591278934e-30,true,3,false,0.0004537,"[4.969793004253981, 1.191204529350223]","[0.12249553087948825, -0.3423467875721143]",0 +9,1.702209400015085e-31,true,4,false,0.0006301,"[4.96979300425394, 1.1912045293502254]","[-0.9204024669915305, -1.2627650563754986]",0 +10,7.968513078100302e-32,true,4,false,0.0006387,"[4.969793004253918, 1.191204529350227]","[-1.425317850889396, -0.13188760801442104]",1 +11,1.1980422091934478e-30,true,3,false,0.0006252,"[4.969793004253957, 1.1912045293502245]","[-0.15268667522019008, -0.17239262787204485]",0 +12,1.5522176898026683e-31,true,3,false,0.000804,"[4.969793004253927, 1.1912045293502265]","[1.3023574705316272, 0.5077729828299388]",0 +13,1.2764725426287269e-30,true,3,false,0.0009039,"[4.969793004253947, 1.1912045293502251]","[0.15426908206241488, 1.5402712760936221]",0 +14,5.3396474586135005e-30,true,3,false,0.0007302,"[4.969793004253985, 1.1912045293502227]","[-1.7267252812920018, 1.0219210821259985]",0 +15,1.058419851027467e-31,true,3,false,0.0007494,"[4.969793004253948, 1.191204529350225]","[0.2747757058146626, 0.1720449857423505]",0 +16,2.0380276004360407e-30,true,3,false,0.0005622,"[4.969793004253965, 1.191204529350224]","[1.0110359111683276, -0.17639294266435857]",0 +17,5.201360867700783e-31,true,4,false,0.00058,"[4.969793004253942, 1.1912045293502254]","[-2.136663990166246, -0.006788132262980114]",0 +18,1.0359523636777318e-31,true,4,false,0.0006136,"[4.969793004253933, 1.1912045293502258]","[-1.2334796855846475, 0.23491144426446822]",0 +19,4.94134966795121e-30,true,3,false,0.0004195,"[4.969793004253996, 1.191204529350222]","[-0.2143326300938984, -0.5149354181924408]",0 +20,1.4614007105013984e-30,true,3,false,0.0006631,"[4.9697930042539635, 1.191204529350224]","[-0.6336756499029971, 1.4154829458615907]",0 diff --git a/src/GMMTools.jl b/src/GMMTools.jl index 7a050c9..b709f55 100644 --- a/src/GMMTools.jl +++ b/src/GMMTools.jl @@ -12,6 +12,7 @@ using StatsAPI # for (Bayesian) bootstrap using StatsBase # take samples +using StatsModels using Distributions # Dirichlet distribution for bootstrap using DelimitedFiles diff --git a/src/functions_estimation.jl b/src/functions_estimation.jl index 23d6fd3..949990e 100644 --- a/src/functions_estimation.jl +++ b/src/functions_estimation.jl @@ -1,51 +1,3 @@ -#= -TODOS: -1. add try ... catch blocks -1. add optimizer options / variants. Where to save the optimizer-specific options? kwargs. -1. save bootstrap weights? -1. add parameter names in the problem object -1. switch to PrettyTables.jl (cf Peter's suggestion) -=# - - -# Base.@kwdef mutable struct GMMProblem -# data -# cache = nothing -# W=I # weight Matrix -# theta0::Array -# weights # weights for each observation (e.g. used in Bayesian bootstrap) -# theta_names::Union{Vector{String}, Nothing} = nothing -# end - -# function create_GMMProblem(; -# data, -# cache=nothing, -# W=I, -# theta0, -# weights=nothing, -# theta_names::Union{Vector{String}, Nothing} = nothing) - -# if isa(theta0, Vector) -# theta0 = Matrix(Transpose(theta0)) -# end - -# if isnothing(theta_names) -# nparams = size(theta0, 2) -# theta_names = ["θ_" * string(i) for i=1:nparams] -# end - -# return GMMProblem(data, cache, W, theta0, weights, theta_names) -# end - -# function Base.show(io::IO, prob::GMMProblem) -# println("GMM Problem, fields:") -# println("- data") -# !isnothing(prob.cache) && println("- cache") -# println("- W = weighting matrix for GMM") -# !isnothing(prob.theta_names) && println("- theta_names ", prob.theta_names) -# println("- theta0 = initial conditions ", prob.theta0) -# println("- weights = observation weights ") -# end Base.@kwdef mutable struct GMMFit theta0::Vector diff --git a/src/functions_regtable.jl b/src/functions_regtable.jl index 8f49f58..7f84a02 100644 --- a/src/functions_regtable.jl +++ b/src/functions_regtable.jl @@ -1,5 +1,5 @@ -Base.@kwdef struct GMMResultTable <: RegressionModel +Base.@kwdef struct GMMModel <: RegressionModel coef::Vector{Float64} # Vector of coefficients vcov::Matrix{Float64} # Covariance matrix vcov_type::CovarianceEstimator @@ -38,24 +38,29 @@ Base.@kwdef struct GMMResultTable <: RegressionModel end -has_iv(m::GMMResultTable) = m.F_kp !== nothing -has_fe(m::GMMResultTable) = false - -StatsAPI.coef(m::GMMResultTable) = m.coef -StatsAPI.coefnames(m::GMMResultTable) = m.coefnames -StatsAPI.responsename(m::GMMResultTable) = m.responsename -StatsAPI.vcov(m::GMMResultTable) = m.vcov -StatsAPI.nobs(m::GMMResultTable) = m.nobs -StatsAPI.dof(m::GMMResultTable) = m.dof -StatsAPI.dof_residual(m::GMMResultTable) = m.dof_residual -StatsAPI.r2(m::GMMResultTable) = r2(m, :devianceratio) -StatsAPI.islinear(m::GMMResultTable) = true -StatsAPI.deviance(m::GMMResultTable) = rss(m) -StatsAPI.nulldeviance(m::GMMResultTable) = m.tss -StatsAPI.rss(m::GMMResultTable) = m.rss -StatsAPI.mss(m::GMMResultTable) = nulldeviance(m) - rss(m) +has_iv(m::GMMModel) = m.F_kp !== nothing +has_fe(m::GMMModel) = false + +# RegressionTables.get_coefname(x::Tuple{Vararg{Term}}) = RegressionTables.get_coefname.(x) +# RegressionTables.replace_name(x::Tuple{Vararg{Any}}, a::Dict{String, String}, b::Dict{String, String}) = [RegressionTables.replace_name(x[i], a, b) for i=1:length(x)] + +RegressionTables.formula(m::GMMModel) = term(m.responsename) ~ sum(term.(String.(m.coefnames))) + +StatsAPI.coef(m::GMMModel) = m.coef +StatsAPI.coefnames(m::GMMModel) = m.coefnames +StatsAPI.responsename(m::GMMModel) = m.responsename +StatsAPI.vcov(m::GMMModel) = m.vcov +StatsAPI.nobs(m::GMMModel) = m.nobs +StatsAPI.dof(m::GMMModel) = m.dof +StatsAPI.dof_residual(m::GMMModel) = m.dof_residual +StatsAPI.r2(m::GMMModel) = r2(m, :devianceratio) +StatsAPI.islinear(m::GMMModel) = true +StatsAPI.deviance(m::GMMModel) = rss(m) +StatsAPI.nulldeviance(m::GMMModel) = m.tss +StatsAPI.rss(m::GMMModel) = m.rss +StatsAPI.mss(m::GMMModel) = nulldeviance(m) - rss(m) # StatsModels.formula(m::GMMResultTable) = m.formula_schema -dof_fes(m::GMMResultTable) = m.dof_fes +dof_fes(m::GMMModel) = m.dof_fes function vcov(r::GMMFit) if isnothing(r.vcov) @@ -74,7 +79,7 @@ function vcov_method(r::GMMFit) end end -function GMMResultTable(r::GMMFit) +function GMMModel(r::GMMFit) nobs = r.N @@ -87,7 +92,7 @@ function GMMResultTable(r::GMMFit) r.theta_names = ["theta_$i" for i=1:length(r.theta_hat)] end - GMMResultTable( + GMMModel( coef = r.theta_hat, vcov = vcov(r), vcov_type=vcov_method(r), @@ -95,7 +100,7 @@ function GMMResultTable(r::GMMFit) fe=DataFrame(), fekeys=[], coefnames=r.theta_names, - responsename="", + responsename="a", # formula::FormulaTerm # Original formula # formula_schema::FormulaTerm # Schema for predict contrasts=Dict(), @@ -113,11 +118,11 @@ end # TODO: integrate better with RegressionModels, allow mixed inputs etc. Should be easy. function regtable(r::GMMFit) - RegressionTables.regtable(GMMResultTable(r); - labels = Dict("__LABEL_ESTIMATOR_OLS__" => "GMM"), - renderSettings = asciiOutput()) + RegressionTables.regtable(GMMModel(r), render = AsciiTable()) end + # labels = Dict("__LABEL_ESTIMATOR_OLS__" => "GMM"), + ### Table # function coef(r::GMMResult)