Skip to content
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
5 changes: 5 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
MixedModels v5.2.0 Release Notes
==============================
- The use of the `wts` keyword argument has been deprecated in favor of the keyword argument `weights`, in line with the deprecation in GLM.jl v1.9.1. The usage (and subsequent interpretation) remains otherwise unchanged. [#873]

MixedModels v5.1.0 Release Notes
==============================
- Nesting checks for the likelihoodratio test have been slightly tweaked to be more robust, at the cost of being slightly slower. In particular, the comparison of models with pre-centered variables with those with variables centered via StandardizedPredictors.jl was previously incorrectly rejected as non-nested, but should be correctly accepted as nested now. Additionally, some further logging messages are emitted when a nesting check fails. [#867]
Expand Down Expand Up @@ -710,3 +714,4 @@ Package dependencies
[#864]: https://github.com/JuliaStats/MixedModels.jl/issues/864
[#865]: https://github.com/JuliaStats/MixedModels.jl/issues/865
[#867]: https://github.com/JuliaStats/MixedModels.jl/issues/867
[#873]: https://github.com/JuliaStats/MixedModels.jl/issues/873
4 changes: 2 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "MixedModels"
uuid = "ff71e718-51f3-5ec2-a782-8ffcbfa3c316"
author = ["Phillip Alday <[email protected]>", "Douglas Bates <[email protected]>"]
version = "5.1.0"
version = "5.2.0"

[deps]
Arrow = "69666777-d1a9-59fb-9406-91d4454c9d45"
Expand Down Expand Up @@ -73,7 +73,7 @@ StableRNGs = "0.1, 1"
StaticArrays = "0.11, 0.12, 1"
Statistics = "1"
StatsAPI = "1.5"
StatsBase = "0.31, 0.32, 0.33, 0.34"
StatsBase = "0.34"
StatsFuns = "0.8, 0.9, 1"
StatsModels = "0.7"
StructTypes = "1"
Expand Down
3 changes: 2 additions & 1 deletion docs/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,14 @@ StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91"
StatsModels = "3eaba693-59b7-5ba5-a881-562e759f1c8d"

[compat]
AlgebraOfGraphics = "0.12"
BenchmarkTools = "1"
DataFrames = "1"
Documenter = "1.3"
FreqTables = "0.4"
Gadfly = "1"
StatsAPI = "1.5"
StatsBase = "0.33"
StatsBase = "0.34"

[sources.MixedModels]
path = ".."
14 changes: 7 additions & 7 deletions docs/src/ecosystem.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Several packages extend the functionality of MixedModels.jl, both in ways specif

```@example Ecosystem
using MixedModels
progress = false
progress = isinteractive()
```

```@example Ecosystem
Expand Down Expand Up @@ -182,16 +182,16 @@ Effects are particularly nice for visualizing the model fit and its predictions.
using AlgebraOfGraphics # like ggplot2, but an algebra instead of a grammar
using CairoMakie

plt1 = data(eff_logit) *
mapping(:age, :use; color=:anych) *
(visual(Lines) + mapping(; lower=:lower, upper=:upper) * visual(LinesFill))
plt1 = data(eff_logit) * mapping(:age; color=:anych) *
(mapping(:use) * visual(Lines) +
mapping(:lower, :upper) * visual(Band; alpha=0.3))
draw(plt1)
```

```@example Ecosystem
plt2 = data(eff_prob) *
mapping(:age, :use; color=:anych => "children") *
(visual(Lines) + mapping(; lower=:lower, upper=:upper) * visual(LinesFill))
plt2 = data(eff_prob) * mapping(:age; color=:anych) *
(mapping(:use) * visual(Lines) +
mapping(:lower, :upper) * visual(Band; alpha=0.3))
draw(plt2)
```

Expand Down
2 changes: 1 addition & 1 deletion src/MixedModels.jl
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ using StatsAPI: dof, dof_residual, fit, fit!, fitted, isfitted, islinear, levera
using StatsAPI:
loglikelihood, meanresponse, modelmatrix, nobs, pvalue, predict, r2, residuals
using StatsAPI: response, responsename, stderror, vcov, weights
using StatsBase: StatsBase, CoefTable, model_response, summarystats
using StatsBase: StatsBase, CoefTable, model_response, summarystats, FrequencyWeights
using StatsFuns: chisqccdf, log2π, normccdf
using StatsModels: StatsModels, AbstractContrasts, AbstractTerm, CategoricalTerm
using StatsModels: ConstantTerm, DummyCoding, EffectsCoding, FormulaTerm, FunctionTerm
Expand Down
32 changes: 23 additions & 9 deletions src/generalizedlinearmixedmodel.jl
Original file line number Diff line number Diff line change
Expand Up @@ -177,14 +177,17 @@
tbl::Tables.ColumnTable,
d::Distribution,
l::Link=canonicallink(d);
wts=[],
weights=[],
wts=nothing,
contrasts=Dict{Symbol,Any}(),
offset=[],
amalgamate=true,
kwargs...,
)
return fit!(
GeneralizedLinearMixedModel(f, tbl, d, l; wts, offset, contrasts, amalgamate);
GeneralizedLinearMixedModel(
f, tbl, d, l; weights, wts, offset, contrasts, amalgamate
);
kwargs...,
)
end
Expand Down Expand Up @@ -368,12 +371,21 @@
tbl::Tables.ColumnTable,
d::Distribution,
l::Link=canonicallink(d);
wts=[],
weights=[],
wts=nothing,
offset=[],
contrasts=Dict{Symbol,Any}(),
amalgamate=true,
)
if isa(d, Binomial) && isempty(wts)
if wts !== nothing
Base.depwarn(
"`wts` keyword argument is deprecated, use `weights` instead",
:GeneralizedLinearMixedModel,
)
weights = wts
end

if isa(d, Binomial) && isempty(weights)
d = Bernoulli()
end
(isa(d, Normal) && isa(l, IdentityLink)) && throw(
Expand All @@ -386,13 +398,13 @@
the authors gain a better understanding of those cases."""
end

LMM = LinearMixedModel(f, tbl; contrasts, wts, amalgamate)
LMM = LinearMixedModel(f, tbl; contrasts, weights, amalgamate)
y = copy(LMM.y)
constresponse = all(==(first(y)), y)
# the sqrtwts field must be the correct length and type but we don't know those
# until after the model is constructed if wt is empty. Because a LinearMixedModel
# type is immutable, another one must be created.
if isempty(wts)
if isempty(weights)
LMM = LinearMixedModel(
LMM.formula,
LMM.reterms,
Expand Down Expand Up @@ -421,10 +433,12 @@
# TODO: construct GLM by hand so that we skip collinearity checks
# TODO: extend this so that we never fit a GLM when initializing from LMM
dofit = size(X, 2) != 0 # GLM.jl kwarg
wtkwarg = pkgversion(GLM) >= v"1.9.1" ? :weights : :wts
weights = convert(Vector{T}, weights)
gl = glm(X, y, d, l;
wts=convert(Vector{T}, wts),
wtkwarg => pkgversion(GLM) >= v"1.9.1" ? FrequencyWeights(weights) : weights,
dofit,
offset=convert(Vector{T}, offset))
:offset => convert(Vector{T}, offset))
β = dofit ? coef(gl) : T[]
u = [fill(zero(eltype(y)), vsize(t), nlevs(t)) for t in LMM.reterms]
# vv is a template vector used to initialize fields for AGQ
Expand All @@ -441,7 +455,7 @@
zero.(u),
gl.rr,
similar(y),
oftype(y, wts),
weights,
similar(vv),
similar(vv),
similar(vv),
Expand Down Expand Up @@ -741,7 +755,7 @@
io::IO, ::MIME"text/plain", m::GeneralizedLinearMixedModel{T,D}
) where {T,D}
if m.optsum.feval < 0
@warn("Model has not been fit")

Check warning on line 758 in src/generalizedlinearmixedmodel.jl

View workflow job for this annotation

GitHub Actions / Documentation

Model has not been fit
return nothing
end
nAGQ = m.LMM.optsum.nAGQ
Expand Down
37 changes: 21 additions & 16 deletions src/linearmixedmodel.jl
Original file line number Diff line number Diff line change
Expand Up @@ -40,20 +40,17 @@ struct LinearMixedModel{T<:AbstractFloat} <: MixedModel{T}
optsum::OptSummary{T}
end

function LinearMixedModel(
f::FormulaTerm, tbl; contrasts=Dict{Symbol,Any}(), wts=[], σ=nothing, amalgamate=true
)
return LinearMixedModel(
f::FormulaTerm, Tables.columntable(tbl); contrasts, wts, σ, amalgamate
)
function LinearMixedModel(f::FormulaTerm, tbl; kwargs...)
return LinearMixedModel(f::FormulaTerm, Tables.columntable(tbl); kwargs...)
end

const _MISSING_RE_ERROR = ArgumentError(
"Formula contains no random effects; this isn't a mixed model. Perhaps you want to use GLM.jl?"
)

function LinearMixedModel(
f::FormulaTerm, tbl::Tables.ColumnTable; contrasts=Dict{Symbol,Any}(), wts=[],
f::FormulaTerm, tbl::Tables.ColumnTable; contrasts=Dict{Symbol,Any}(), wts=nothing,
weights=[],
σ=nothing, amalgamate=true,
)
fvars = StatsModels.termvars(f)
Expand All @@ -65,6 +62,13 @@ function LinearMixedModel(
),
)

if wts !== nothing
Base.depwarn(
"`wts` keyword argument is deprecated, use `weights` instead", :LinearMixedModel
)
weights = wts
end

# TODO: perform missing_omit() after apply_schema() when improved
# missing support is in a StatsModels release
tbl, _ = StatsModels.missing_omit(tbl, f)
Expand All @@ -76,11 +80,11 @@ function LinearMixedModel(

y, Xs = modelcols(form, tbl)

return LinearMixedModel(y, Xs, form, wts, σ, amalgamate)
return LinearMixedModel(y, Xs, form, weights, σ, amalgamate)
end

"""
LinearMixedModel(y, Xs, form, wts=[], σ=nothing, amalgamate=true)
LinearMixedModel(y, Xs, form, weights=[], σ=nothing, amalgamate=true)

Private constructor for a LinearMixedModel.

Expand All @@ -96,7 +100,7 @@ function LinearMixedModel(
y::AbstractArray,
Xs::Tuple, # can't be more specific here without stressing the compiler
form::FormulaTerm,
wts=[],
weights=[],
σ=nothing,
amalgamate=true,
)
Expand Down Expand Up @@ -132,12 +136,12 @@ function LinearMixedModel(
end
isempty(reterms) && throw(_MISSING_RE_ERROR)
return LinearMixedModel(
convert(Array{T}, y), only(feterms), reterms, form, wts, σ, amalgamate
convert(Array{T}, y), only(feterms), reterms, form, weights, σ, amalgamate
)
end

"""
LinearMixedModel(y, feterm, reterms, form, wts=[], σ=nothing; amalgamate=true)
LinearMixedModel(y, feterm, reterms, form, weights=[], σ=nothing; amalgamate=true)

Private constructor for a `LinearMixedModel` given already assembled fixed and random effects.

Expand All @@ -155,7 +159,7 @@ function LinearMixedModel(
feterm::FeTerm{T},
reterms::AbstractVector{<:AbstractReMat{T}},
form::FormulaTerm,
wts=[],
weights=[],
σ=nothing,
amalgamate=true,
) where {T}
Expand All @@ -168,7 +172,7 @@ function LinearMixedModel(

sort!(reterms; by=nranef, rev=true)
Xy = FeMat(feterm, vec(y))
sqrtwts = map!(sqrt, Vector{T}(undef, length(wts)), wts)
sqrtwts = map!(sqrt, Vector{T}(undef, length(weights)), weights)
reweight!.(reterms, Ref(sqrtwts))
reweight!(Xy, sqrtwts)
A, L = createAL(reterms, Xy)
Expand Down Expand Up @@ -206,12 +210,13 @@ end
function StatsAPI.fit(::Type{LinearMixedModel},
f::FormulaTerm,
tbl::Tables.ColumnTable;
wts=[],
weights=[],
wts=nothing,
contrasts=Dict{Symbol,Any}(),
σ=nothing,
amalgamate=true,
kwargs...)
lmod = LinearMixedModel(f, tbl; contrasts, wts, σ, amalgamate)
lmod = LinearMixedModel(f, tbl; contrasts, weights, wts, σ, amalgamate)
return fit!(lmod; kwargs...)
end

Expand Down
Loading