Skip to content

Commit

Permalink
Merge pull request #146 from junder873/flexible-below-statistics
Browse files Browse the repository at this point in the history
Internal adjustments to below statistics to increase flexibility and necessary changes to standardization to match
  • Loading branch information
junder873 authored Feb 15, 2024
2 parents 8a1f0ac + d26d7e2 commit c53fcdb
Show file tree
Hide file tree
Showing 10 changed files with 254 additions and 31 deletions.
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "RegressionTables"
uuid = "d519eb52-b820-54da-95a6-98e1306fdade"
authors = ["Johannes Boehm <[email protected]>"]
version = "0.6.2"
version = "0.7.0"

[deps]
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
Expand Down
22 changes: 21 additions & 1 deletion docs/src/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@ RegressionTables.reorder_nms_list
RegressionTables.drop_names!
RegressionTables.add_blank
RegressionTables.missing_vars
RegressionTables.other_stats
RegressionTables.add_element!
```

Expand All @@ -83,4 +82,25 @@ This section describes how different types are displayed. Throughout this packag

```@docs
Base.repr
```

## New RegressionModel Types

This package is designed to be generally compatible with the [RegressionModel abstraction](https://juliastats.org/StatsBase.jl/latest/statmodels/). It has special conditions defined around four commonly used packages ([FixedEffectModels.jl](https://github.com/matthieugomez/FixedEffectModels.jl), [GLM.jl](https://github.com/JuliaStats/GLM.jl), [GLFixedEffectModels.jl](https://github.com/jmboehm/GLFixedEffectModels.jl) and [MixedModels.jl](https://github.com/JuliaStats/MixedModels.jl)). It is possible to add new models to this list, either by creating an extension for this package or by creating the necessary items in an independent package.

For any new `RegressionModel`, there may be a need to define the following functions for the package to work correctly. Many of these will work without any issues if following the StatsModels API, and many of the others are useful for customizing how the regression result is displayed. It is also possible to redefine how [`RegressionTables.AbstractRegressionStatistic`](@ref) are displayed.

```@docs
RegressionTables._formula
RegressionTables._responsename
RegressionTables._coefnames
RegressionTables._coef
RegressionTables._stderror
RegressionTables._dof_residual
RegressionTables._pvalue
RegressionTables.other_stats
RegressionTables.default_regression_statistics(::RegressionModel)
RegressionTables.can_standardize
RegressionTables.standardize_coef_values
RegressionTables.RegressionType
```
1 change: 1 addition & 0 deletions docs/src/customization.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ RegressionTables.default_regression_statistics
RegressionTables.default_print_randomeffects
RegressionTables.default_print_clusters
RegressionTables.default_use_relabeled_values
RegressionTables.default_confint_level
```

## Other Defaults
Expand Down
70 changes: 70 additions & 0 deletions docs/src/examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,8 @@ Within-R2 0.642 0.598 0.391

### ConfInt (Confidence Interval)

Confidence level defaults to the 95th percentile:

```jldoctest
regtable(rr1,rr2,rr3,rr4; below_statistic = ConfInt)
Expand Down Expand Up @@ -209,6 +211,41 @@ Within-R2 0.642 0.598
------------------------------------------------------------------------------------------------
```

Set the Confidence Interval level either by setting [`RegressionTables.default_confint_level`](@ref) or by adjusting the `confint_level` keyword argument

```jldoctest
regtable(rr1,rr2,rr3,rr4; below_statistic = ConfInt, confint_level=0.9, align=:c)
# output
-------------------------------------------------------------------------------------------------
SepalLength SepalWidth
--------------------------------------------------- ----------------
(1) (2) (3) (4)
-------------------------------------------------------------------------------------------------
(Intercept) 6.526***
(5.734, 7.319)
SepalWidth -0.223 0.432*** 0.516***
(-0.480, 0.033) (0.297, 0.567) (0.345, 0.688)
PetalLength 0.776*** 0.723*** -0.188*
(0.669, 0.882) (0.510, 0.937) (-0.326, -0.049)
PetalWidth -0.625 0.626***
(-1.211, -0.038) (0.421, 0.830)
PetalLength & PetalWidth 0.066
(-0.045, 0.177)
SepalLength 0.378***
(0.269, 0.486)
-------------------------------------------------------------------------------------------------
Species Fixed Effects Yes Yes Yes
isSmall Fixed Effects Yes
-------------------------------------------------------------------------------------------------
N 150 150 150 150
R2 0.014 0.863 0.868 0.635
Within-R2 0.642 0.598 0.391
-------------------------------------------------------------------------------------------------
```

## Standard Errors on same line as coefficient

```jldoctest
Expand Down Expand Up @@ -1240,6 +1277,39 @@ Pseudo R2 0.006 0.811 0.347 0.297
------------------------------------------------------------------
```

It is also possible to standardize some coefficients and not others

```jldoctest
lm1 = lm(@formula(SepalLength ~ SepalWidth), df);
regtable(lm1, lm1, rr7, rr7; standardize_coef=[false, true, false, true])
# output
---------------------------------------------------------
SepalLength isSmall
------------------- ---------------------
(1) (2) (3) (4)
---------------------------------------------------------
(Intercept) 6.526*** 7.881*** 10.189*** 21.894***
(0.479) (0.578) (2.607) (5.601)
SepalWidth -0.223 -0.118
(0.155) (0.082)
SepalLength -3.519*** -6.260***
(0.697) (1.240)
PetalLength 3.580*** 13.578***
(0.708) (2.686)
PetalWidth -3.637** -5.957**
(1.127) (1.846)
---------------------------------------------------------
Estimator OLS OLS Binomial Binomial
---------------------------------------------------------
N 150 150 150 150
R2 0.014 0.014
Pseudo R2 0.006 0.006 0.297 0.297
---------------------------------------------------------
```

## Show Clustered Standard Errors

Displays whether or not the standard errors are clustered and in what ways.
Expand Down
1 change: 0 additions & 1 deletion docs/src/regression_statistics.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ Filter = t -> typeof(t) === DataType && t <: RegressionTables.AbstractUnderStati

```@docs
RegressionTables.CoefValue
RegressionTables.RegressionType
RegressionTables.HasControls
RegressionTables.RegressionNumbers
RegressionTables.FixedEffectValue
Expand Down
8 changes: 6 additions & 2 deletions ext/RegressionTablesGLMExt.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,12 @@ RegressionTables.default_regression_statistics(rr::StatsModels.TableRegressionMo

RegressionTables.RegressionType(x::StatsModels.TableRegressionModel{T}) where {T<:GLM.AbstractGLM} = RegressionType(x.model)
RegressionTables.RegressionType(x::StatsModels.TableRegressionModel{T}) where {T<:LinearModel} = RegressionType(x.model)
RegressionTables.standardize_coef_values(x::StatsModels.TableRegressionModel, coefvalues, coefstderrors) =
RegressionTables.standardize_coef_values(std(modelmatrix(x), dims=1)[1, :], std(response(x)), coefvalues, coefstderrors)

# k is which coefficient or standard error to standardize
RegressionTables.standardize_coef_values(x::StatsModels.TableRegressionModel, val, k) =
RegressionTables.standardize_coef_values(std(modelmatrix(x)[:, k]), std(response(x)), val)

RegressionTables.can_standardize(x::StatsModels.TableRegressionModel) = true

RegressionTables.RegressionType(x::LinearModel) = RegressionType(Normal())
RegressionTables.RegressionType(x::GLM.LmResp) = RegressionType(Normal())
Expand Down
7 changes: 5 additions & 2 deletions ext/RegressionTablesMixedModelsExt.jl
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,11 @@ function RegressionTables._coefnames(x::MixedModel)
out
end

RegressionTables.standardize_coef_values(x::MixedModel, coefvalues, coefstderrors) =
RegressionTables.standardize_coef_values(std(modelmatrix(x), dims=1)[1, :], std(response(x)), coefvalues, coefstderrors)
# k is which coefficient or standard error to standardize
RegressionTables.standardize_coef_values(x::MixedModel, val, k) =
RegressionTables.standardize_coef_values(std(modelmatrix(x)[:, k]), std(response(x)), val)

RegressionTables.can_standardize(x::MixedModel) = true

function RegressionTables.other_stats(x::MixedModel, s::Symbol)
if s == :randomeffects
Expand Down
37 changes: 29 additions & 8 deletions src/RegressionStatistics.jl
Original file line number Diff line number Diff line change
Expand Up @@ -462,44 +462,57 @@ abstract type AbstractUnderStatistic <: AbstractRegressionData end
struct TStat <: AbstractUnderStatistic
val::Float64
end
TStat(se, coef, dof=0)
TStat(rr::RegressionModel, k::Int; vargs...)
The t-statistic of a coefficient.
"""
struct TStat <: AbstractUnderStatistic
val::Float64
end
TStat(se, coef, dof=0) = TStat(coef / se)
TStat(rr::RegressionModel, k::Int; vargs...) = TStat(_coef(rr)[k] / _stderror(rr)[k])

"""
struct StdError <: AbstractUnderStatistic
val::Float64
end
StdError(se, coef, dof=0)
StdError(rr::RegressionModel, k::Int; standardize=false, vargs...)
The standard error of a coefficient.
"""
struct StdError <: AbstractUnderStatistic
val::Float64
end
StdError(se, coef, dof=0) = StdError(se)
function StdError(rr::RegressionModel, k::Int; standardize=false, vargs...)
if standardize
StdError(standardize_coef_values(rr, _stderror(rr)[k], k))
else
StdError(_stderror(rr)[k])
end
end

"""
struct ConfInt <: AbstractUnderStatistic
val::Tuple{Float64, Float64}
end
ConfInt(se, coef, dof; level=default_confint_level())
ConfInt(rr::RegressionModel, k::Int; level=0.95, standardize=false, vargs...)
The confidence interval of a coefficient. The default confidence
level is 95% (can be changed by setting
`RegressionTable.default_confint_level() = 0.90` or similar).
`RegressionTable.default_confint_level(render::AbstractRenderType, rr) = 0.90` or similar).
"""
struct ConfInt <: AbstractUnderStatistic
val::Tuple{Float64, Float64}
end
default_confint_level() = 0.95
function ConfInt(se, coef, dof; level=default_confint_level())

function ConfInt(rr::RegressionModel, k::Int; level=0.95, standardize=false, vargs...)
@assert 0 < level < 1 "Confidence level must be between 0 and 1"
se = _stderror(rr)[k]
coef = _coef(rr)[k]
dof = _dof_residual(rr)
if standardize
se = standardize_coef_values(rr, se, k)
coef = standardize_coef_values(rr, coef, k)
end
scale = quantile(TDist(dof), 1 - (1-level) / 2)
ConfInt((coef - scale * se, coef + scale * se))
end
Expand All @@ -519,6 +532,14 @@ struct CoefValue <: AbstractRegressionData
val::Float64
pvalue::Float64
end
function CoefValue(rr::RegressionModel, k::Int; standardize=false, vargs...)
val = _coef(rr)[k]
p = _pvalue(rr)[k]
if standardize
val = standardize_coef_values(rr, val, k)
end
CoefValue(val, p)
end
value(x::CoefValue) = x.val
value_pvalue(x::CoefValue) = x.pvalue
value_pvalue(x::Missing) = missing
Expand Down
Loading

2 comments on commit c53fcdb

@junder873
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JuliaRegistrator register()

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Registration pull request created: JuliaRegistries/General/100979

Tip: Release Notes

Did you know you can add release notes too? Just add markdown formatted text underneath the comment after the text
"Release notes:" and it will be added to the registry PR, and if TagBot is installed it will also be added to the
release that TagBot creates. i.e.

@JuliaRegistrator register

Release notes:

## Breaking changes

- blah

To add them here just re-invoke and the PR will be updated.

Tagging

After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.

This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via:

git tag -a v0.7.0 -m "<description of version>" c53fcdbf0ef0f4ce865f3dca9dd24129ff2fe772
git push origin v0.7.0

Please sign in to comment.