Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release 0.2.5 #11

Merged
merged 3 commits into from
Feb 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "AnovaFixedEffectModels"
uuid = "e4965305-65d6-464d-9c03-ae3e5cffadab"
authors = ["yufongpeng <54415349+yufongpeng@users.noreply.github.com> and contributors"]
version = "0.2.4"
version = "0.2.5"

[deps]
AnovaBase = "946dddda-6a23-4b48-8e70-8e60d9b8d680"
Expand All @@ -16,11 +16,11 @@ StatsModels = "3eaba693-59b7-5ba5-a881-562e759f1c8d"
Tables = "bd369af6-aec1-5ad0-b16a-f7cc5008161c"

[compat]
AnovaBase = "0.7"
AnovaBase = "0.8"
Distributions = "0.23, 0.24, 0.25"
FixedEffectModels = "1.3, 1.4, 1.5, 1.6, 1.7, 1.8"
Reexport = "0.2, 1"
StatsBase = "0.33, 0.34"
StatsModels = "0.7"
Tables = "1.7"
julia = "1.6, 1.7, 1.8, 1.9"
julia = "1.6, 1.7, 1.8, 1.9, 1.10"
4 changes: 2 additions & 2 deletions src/AnovaFixedEffectModels.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import StatsBase: fit!, fit
import StatsModels: TableRegressionModel, vectorize, width, apply_schema,
ModelFrame, ModelMatrix, columntable, asgn

using AnovaBase: select_super_interaction, extract_contrasts, canonicalgoodnessoffit, subformula, dof_asgn, lrt_nested, ftest_nested, _diff, _diffn, has_intercept
using AnovaBase: select_super_interaction, extract_contrasts, canonicalgoodnessoffit, subformula, dof_asgn, lrt_nested, ftest_nested, _diff, _diffn, testname
import AnovaBase: anova, nestedmodels, anovatable, prednames, predictors, formula
using Tables: columntable

import Base: show
export anova_lfe, lfe

include("anova.jl")
Expand Down
12 changes: 6 additions & 6 deletions src/anova.jl
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,10 @@ function anova(::Type{FTest},
end
elseif aovm.type == 2
fstat = ntuple(last(fullasgn) - offset) do fix
select1 = sort!(collect(select_super_interaction(fullpred, fix + offset)))
select2 = setdiff(select1, fix + offset)
select1 = findall(in(select1), fullasgn)
select2 = findall(in(select2), fullasgn)
s1 = sort!(collect(select_super_interaction(fullpred, fix + offset)))
s2 = setdiff(s1, fix + offset)
select1 = findall(in(s1), fullasgn)
select2 = findall(in(s2), fullasgn)
(β[select1]' * (varβ[select1, select1] \ β[select1]) - β[select2]' * (varβ[select2, select2] \ β[select2])) / df[fix]
end
else
Expand All @@ -83,7 +83,7 @@ function anova(::Type{FTest},
σ² = rss(aovm.model) / dfr
devs = @. fstat * σ² * df
pvalue = @. ccdf(FDist(df, dfr), abs(fstat))
AnovaResult{FTest}(aovm, df, devs, fstat, pvalue, NamedTuple())
AnovaResult(aovm, FTest, df, devs, fstat, pvalue, NamedTuple())
end

# =================================================================================================================
Expand All @@ -102,7 +102,7 @@ function anova(::Type{FTest},
dev = rss.(models)
# check comparable and nested
check && @warn "Could not check whether models are nested: results may not be meaningful"
ftest_nested(NestedModels{M}(models), df, dfr, dev, last(dev) / last(dfr))
ftest_nested(NestedModels(models), df, dfr, dev, last(dev) / last(dfr))
end

function anova(::Type{FTest}, aovm::NestedModels{M}) where {M <: FixedEffectModel}
Expand Down
5 changes: 2 additions & 3 deletions src/fit.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# ==========================================================================================================
# Backend funcion
formula(model::T) where {T <: FixedEffectModel} = model.formula
predictors(model::T) where {T <: FixedEffectModel} = model.formula_schema.rhs.terms

# Variable dispersion
Expand All @@ -19,10 +18,10 @@ Generate nested models from modeltype, formula and data. The null model will be
function nestedmodels(modeltype::Type{FixedEffectModel}, f::FormulaTerm, data; null = true, kwargs...)
fullm = lfe(f, data; kwargs...)
predterms = predictors(fullm)
has_intercept(predterms) || (length(predterms) > 1 ? (predterms = predterms[2:end]) : throw(ArgumentError("Empty model is given!")))
hasintercept(predterms) || (length(predterms) > 1 ? (predterms = predterms[2:end]) : throw(ArgumentError("Empty model is given!")))
feterms = filter(isfe, f.rhs)
subm = ntuple(length(predterms) - 1) do i
lfe(FormulaTerm(f.lhs, (predterms[1:i]..., feterms...)), data; kwargs...)
end
NestedModels{FixedEffectModel}(null ? (lfe(FormulaTerm(f.lhs, (ConstantTerm(0), feterms...)), data; kwargs...), subm..., fullm) : (subm..., fullm))
NestedModels(null ? (lfe(FormulaTerm(f.lhs, (ConstantTerm(0), feterms...)), data; kwargs...), subm..., fullm) : (subm..., fullm))
end
57 changes: 56 additions & 1 deletion src/io.jl
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,59 @@ function anovatable(aov::AnovaResult{<: NestedModels{<: FixedEffectModel, N}, FT
],
["DOF", "ΔDOF", "Res.DOF", "R²", "ΔR²", "R²_within", "ΔR²_within", "Res.SS", "Exp.SS", "F value", "Pr(>|F|)"],
rownames, 11, 10)
end
end

function show(io::IO, anovamodel::FullModel{<: T}) where {T <: FixedEffectModel}
println(io, "FullModel for type $(anovamodel.type) test")
println(io)
println(io, "Predictors:")
println(io, join(prednames(anovamodel), ", "))
println(io)
println(io, "Formula:")
println(io, anovamodel.model.formula)
println(io)
println(io, "Coefficients:")
show(io, coeftable(anovamodel.model))
end

function show(io::IO, anovamodel::NestedModels{M, N}) where {M <: FixedEffectModel, N}
println(io, "NestedModels with $N models")
println(io)
println(io, "Formulas:")
for(id, m) in enumerate(anovamodel.model)
println(io, "Model $id: ", m.formula)
end
println(io)
println(io, "Coefficients:")
show(io, coeftable(first(anovamodel.model)))
println(io)
N > 2 && print(io, " .\n" ^ 3)
show(io, coeftable(last(anovamodel.model)))
end

# Show function that delegates to anovatable
function show(io::IO, aov::AnovaResult{<: FullModel{<: FixedEffectModel}, T}) where {T <: GoodnessOfFit}
at = anovatable(aov)
println(io, "Analysis of Variance")
println(io)
println(io, "Type $(anova_type(aov)) test / $(testname(T))")
println(io)
println(io, aov.anovamodel.model.formula)
println(io)
println(io, "Table:")
show(io, at)
end

function show(io::IO, aov::AnovaResult{<: MultiAovModels{<: FixedEffectModel}, T}) where {T <: GoodnessOfFit}
at = anovatable(aov)
println(io,"Analysis of Variance")
println(io)
println(io, "Type $(anova_type(aov)) test / $(testname(T))")
println(io)
for(id, m) in enumerate(aov.anovamodel.model)
println(io, "Model $id: ", m.formula)
end
println(io)
println(io, "Table:")
show(io, at)
end
5 changes: 3 additions & 2 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,14 @@ isapprox(x::NTuple{N, Float64}, y::NTuple{N, Float64}, atol::NTuple{N, Float64}
global aovl1 = AnovaGLM.anova(lm1)
global aovf2 = AFE.anova(fem2, type = 3)
global aovl2 = AnovaGLM.anova(lm2, type = 3)
global aovfs = AFE.anova(NestedModels{FixedEffectModel}(fem0, fem1))
global aovfs = AFE.anova(NestedModels(fem0, fem1))
global aovfs2 = AFE.anova(fem0, fem1)
global aovls = AnovaGLM.anova(lm0, lm1)
@test !(@test_error test_show(aovf1))
@test !(@test_error test_show(aovf1.anovamodel))
@test !(@test_error test_show(aovf2))
@test !(@test_error test_show(aovfs))
@test !(@test_error test_show(aovfs.anovamodel))
@test nobs(aovf1) == nobs(aovl1)
@test last(dof(aovf1)) == dof(aovl1)[end - 1]
@test isapprox(first(deviance(aovf2)), first(deviance(aovl2)))
Expand All @@ -68,7 +70,6 @@ isapprox(x::NTuple{N, Float64}, y::NTuple{N, Float64}, atol::NTuple{N, Float64}
df = DataFrame(y = randn(1000), x = rand(1:5, 1000), z = rand(["1", "2"], 1000), t = 1:1000)
fems1 = nestedmodels(FixedEffectModel, @formula(y ~ t + fe(z) + fe(x)), df)
fems2 = nestedmodels(FixedEffectModel, @formula(y ~ z + t & fe(x)), df)
@test formula(fems1.model[1]).rhs == @formula(y ~ 0 + fe(z) + fe(x)).rhs
@test AFE.predictors(fems2.model[2])[1] == InterceptTerm{true}()
end
end
Expand Down
Loading