From d2504262012dfe2c9160f678b774f20eeb9149d3 Mon Sep 17 00:00:00 2001 From: Douglas Bates Date: Sun, 28 Apr 2024 07:45:24 -0500 Subject: [PATCH 01/13] Update for ExplicitImports check (#765) --- src/MixedModels.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/MixedModels.jl b/src/MixedModels.jl index b3c43c4d4..d03de81cd 100644 --- a/src/MixedModels.jl +++ b/src/MixedModels.jl @@ -6,7 +6,7 @@ using BSplineKit: BSplineKit, BSplineOrder, Natural, Derivative, SplineInterpola using BSplineKit: interpolate using DataAPI: DataAPI, levels, refpool, refarray, refvalue using Distributions: Distributions, Bernoulli, Binomial, Chisq, Distribution, Gamma -using Distributions: InverseGaussian, Normal, Poisson, ccdf, estimate +using Distributions: InverseGaussian, Normal, Poisson, ccdf using GLM: GLM, GeneralizedLinearModel, IdentityLink, InverseLink, LinearModel using GLM: Link, LogLink, LogitLink, ProbitLink, SqrtLink using GLM: canonicallink, glm, linkinv, dispersion, dispersion_parameter @@ -16,10 +16,10 @@ using LinearAlgebra: Diagonal, Hermitian, HermOrSym, I, LAPACK, LowerTriangular using LinearAlgebra: PosDefException, SVD, SymTridiagonal, Symmetric using LinearAlgebra: UpperTriangular, cond, diag, diagind, dot, eigen, isdiag using LinearAlgebra: ldiv!, lmul!, logdet, mul!, norm, normalize, normalize!, qr -using LinearAlgebra: rank, rdiv!, rmul!, svd, tr, tril! +using LinearAlgebra: rank, rdiv!, rmul!, svd, tril! using Markdown: Markdown using MixedModelsDatasets: dataset, datasets -using NLopt: NLopt, Opt, ftol_abs, ftol_rel, initial_step, maxtime, xtol_abs, xtol_rel +using NLopt: NLopt, Opt, ftol_abs, ftol_rel, initial_step, xtol_abs, xtol_rel using PooledArrays: PooledArrays, PooledArray using PrecompileTools: PrecompileTools, @setup_workload, @compile_workload using ProgressMeter: ProgressMeter, Progress, ProgressUnknown, finish!, next! @@ -40,7 +40,7 @@ using StatsModels: HelmertCoding, HypothesisCoding, InteractionTerm, InterceptTe using StatsModels: MatrixTerm, SeqDiffCoding, TableRegressionModel, Term using StatsModels: apply_schema, drop_term, formula, modelcols, term, @formula using StructTypes: StructTypes -using Tables: Tables, columntable, rows +using Tables: Tables, columntable using TypedTables: TypedTables, DictTable, FlexTable, Table export @formula, From c4beee91ed3b13b41b90aa7e913796337a16ac09 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 May 2024 02:29:22 +0000 Subject: [PATCH 02/13] Bump julia-actions/cache from 1 to 2 (#766) Bumps [julia-actions/cache](https://github.com/julia-actions/cache) from 1 to 2. - [Release notes](https://github.com/julia-actions/cache/releases) - [Commits](https://github.com/julia-actions/cache/compare/v1...v2) --- updated-dependencies: - dependency-name: julia-actions/cache dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/benchmark.yml | 2 +- .github/workflows/current.yml | 2 +- .github/workflows/documenter.yml | 2 +- .github/workflows/minimum.yml | 2 +- .github/workflows/nightly.yml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 667c2fe92..655738c3f 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -24,7 +24,7 @@ jobs: - uses: julia-actions/setup-julia@v2 with: version: "1" - - uses: julia-actions/cache@v1 + - uses: julia-actions/cache@v2 - uses: julia-actions/julia-buildpkg@v1 - name: Benchmark run run: | diff --git a/.github/workflows/current.yml b/.github/workflows/current.yml index 0e8a34743..7e2172e36 100644 --- a/.github/workflows/current.yml +++ b/.github/workflows/current.yml @@ -30,7 +30,7 @@ jobs: - uses: julia-actions/setup-julia@v2 with: version: ${{ matrix.julia-version }} - - uses: julia-actions/cache@v1 + - uses: julia-actions/cache@v2 with: cache-compiled: "true" - uses: julia-actions/julia-buildpkg@v1 diff --git a/.github/workflows/documenter.yml b/.github/workflows/documenter.yml index 81a8ccd6a..483fc4b8f 100644 --- a/.github/workflows/documenter.yml +++ b/.github/workflows/documenter.yml @@ -25,7 +25,7 @@ jobs: - uses: julia-actions/setup-julia@v2 with: version: 1.8 - - uses: julia-actions/cache@v1 + - uses: julia-actions/cache@v2 with: cache-compiled: "true" - uses: julia-actions/julia-buildpkg@latest diff --git a/.github/workflows/minimum.yml b/.github/workflows/minimum.yml index 80be46af9..f7e37a65f 100644 --- a/.github/workflows/minimum.yml +++ b/.github/workflows/minimum.yml @@ -28,7 +28,7 @@ jobs: - uses: julia-actions/setup-julia@v2 with: version: ${{ matrix.julia-version }} - - uses: julia-actions/cache@v1 + - uses: julia-actions/cache@v2 with: cache-compiled: "true" - uses: julia-actions/julia-buildpkg@v1 diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 26e85fc56..1f667ca2b 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -28,7 +28,7 @@ jobs: - uses: julia-actions/setup-julia@v2 with: version: ${{ matrix.julia-version }} - - uses: julia-actions/cache@v1 + - uses: julia-actions/cache@v2 with: cache-compiled: true - uses: julia-actions/julia-runtest@v1 From 84a61c28f470e16910b70ad0485c874dcc01b572 Mon Sep 17 00:00:00 2001 From: Phillip Alday Date: Wed, 15 May 2024 21:00:24 +0000 Subject: [PATCH 03/13] delegate as many GLMM properties as possible to internal LMM (#767) * delegate as many GLMM properties as possible to internal LMM * NEWS and version bump --- NEWS.md | 5 +++++ Project.toml | 2 +- src/generalizedlinearmixedmodel.jl | 8 ++++---- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/NEWS.md b/NEWS.md index cc2f91e03..acf1b91cc 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,7 @@ +MixedModels v4.24.0 Release Notes +============================== +* Properties for `GeneralizedLinearMixedModel` now default to delegation to the internal weighted `LinearMixedModel` when that property is not explicitly handled by `GeneralizedLinearMixedModel`. Previously, properties were delegated on an explicit basis, which meant that they had to be added manually as use cases were discovered. The downside to the new approach is that it is now possible to access properties whose definition in the LMM case doesn't match the GLMM definition when the GLMM definition hasn't been explicitly been implemented. [#767] + MixedModels v4.23.1 Release Notes ============================== * Fix for `simulate!` when only the estimable coefficients for a rank-deficient model are provided. [#756] @@ -516,3 +520,4 @@ Package dependencies [#748]: https://github.com/JuliaStats/MixedModels.jl/issues/748 [#755]: https://github.com/JuliaStats/MixedModels.jl/issues/755 [#756]: https://github.com/JuliaStats/MixedModels.jl/issues/756 +[#767]: https://github.com/JuliaStats/MixedModels.jl/issues/767 diff --git a/Project.toml b/Project.toml index 7020d82ac..225f9aa54 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "MixedModels" uuid = "ff71e718-51f3-5ec2-a782-8ffcbfa3c316" author = ["Phillip Alday ", "Douglas Bates ", "Jose Bayoan Santiago Calderon "] -version = "4.23.1" +version = "4.24.0" [deps] Arrow = "69666777-d1a9-59fb-9406-91d4454c9d45" diff --git a/src/generalizedlinearmixedmodel.jl b/src/generalizedlinearmixedmodel.jl index e33429b81..f9f6ad5dc 100644 --- a/src/generalizedlinearmixedmodel.jl +++ b/src/generalizedlinearmixedmodel.jl @@ -489,12 +489,12 @@ function Base.getproperty(m::GeneralizedLinearMixedModel, s::Symbol) σs(m) elseif s == :σρs σρs(m) - elseif s ∈ (:A, :L, :optsum, :reterms, :Xymat, :feterm, :formula, :parmap) - getfield(m.LMM, s) - elseif s ∈ (:dims, :λ, :lowerbd, :corr, :PCA, :rePCA, :X) - getproperty(m.LMM, s) elseif s == :y m.resp.y + elseif !hasfield(GeneralizedLinearMixedModel, s) && s ∈ propertynames(m.LMM, true) + # automatically delegate as much as possible to the internal local linear approximation + # NB: the !hasfield call has to be first since we're calling getproperty() with m.LMM... + getproperty(m.LMM, s) else getfield(m, s) end From 35492585aabb6619e2efa32e621e01855ba480ca Mon Sep 17 00:00:00 2001 From: Phillip Alday Date: Thu, 30 May 2024 14:17:43 +0000 Subject: [PATCH 04/13] import and re-export `lrtest` (#769) --- Project.toml | 2 +- src/MixedModels.jl | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Project.toml b/Project.toml index 225f9aa54..6d31df627 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "MixedModels" uuid = "ff71e718-51f3-5ec2-a782-8ffcbfa3c316" author = ["Phillip Alday ", "Douglas Bates ", "Jose Bayoan Santiago Calderon "] -version = "4.24.0" +version = "4.24.1" [deps] Arrow = "69666777-d1a9-59fb-9406-91d4454c9d45" diff --git a/src/MixedModels.jl b/src/MixedModels.jl index d03de81cd..735b18581 100644 --- a/src/MixedModels.jl +++ b/src/MixedModels.jl @@ -38,7 +38,7 @@ using StatsModels: StatsModels, AbstractContrasts, AbstractTerm, CategoricalTerm using StatsModels: ConstantTerm, DummyCoding, EffectsCoding, FormulaTerm, FunctionTerm using StatsModels: HelmertCoding, HypothesisCoding, InteractionTerm, InterceptTerm using StatsModels: MatrixTerm, SeqDiffCoding, TableRegressionModel, Term -using StatsModels: apply_schema, drop_term, formula, modelcols, term, @formula +using StatsModels: apply_schema, drop_term, formula, lrtest, modelcols, term, @formula using StructTypes: StructTypes using Tables: Tables, columntable using TypedTables: TypedTables, DictTable, FlexTable, Table @@ -114,6 +114,7 @@ export @formula, logdet, loglikelihood, lowerbd, + lrtest, meanresponse, modelmatrix, model_response, From 39dd384602d0b498fa579c6db72d8b3e5add1a3b Mon Sep 17 00:00:00 2001 From: Douglas Bates Date: Thu, 20 Jun 2024 17:44:15 -0500 Subject: [PATCH 05/13] Force return type on pwrss and logdet (#771) --- src/linalg/logdet.jl | 4 ++-- src/linearmixedmodel.jl | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/linalg/logdet.jl b/src/linalg/logdet.jl index e4e084a72..97d637cb5 100644 --- a/src/linalg/logdet.jl +++ b/src/linalg/logdet.jl @@ -25,11 +25,11 @@ lower Cholesky factor. """ function LinearAlgebra.logdet(m::LinearMixedModel{T}) where {T} L = m.L - @inbounds s = sum(j -> LD(L[kp1choose2(j)]), axes(m.reterms, 1)) + @inbounds s = sum(j -> LD(L[kp1choose2(j)]), axes(m.reterms, 1))::T if m.optsum.REML lastL = last(L) s += LD(lastL) # this includes the log of sqrtpwrss s -= log(last(lastL)) # so we need to subtract it from the sum end - return s + s # multiply by 2 b/c the desired det is of the symmetric mat, not the factor + return (s + s)::T # multiply by 2 b/c the desired det is of the symmetric mat, not the factor end diff --git a/src/linearmixedmodel.jl b/src/linearmixedmodel.jl index cc95b1a1a..8ec16f171 100644 --- a/src/linearmixedmodel.jl +++ b/src/linearmixedmodel.jl @@ -50,7 +50,7 @@ function LinearMixedModel( end const _MISSING_RE_ERROR = ArgumentError( - "Formula contains no random effects; this isn't a mixed model. Perhaps you want to use GLM.jl?", + "Formula contains no random effects; this isn't a mixed model. Perhaps you want to use GLM.jl?" ) function LinearMixedModel( @@ -62,7 +62,7 @@ function LinearMixedModel( fvars ⊆ tvars || throw( ArgumentError( - "The following formula variables are not present in the table: $(setdiff(fvars, tvars))", + "The following formula variables are not present in the table: $(setdiff(fvars, tvars))" ), ) @@ -226,7 +226,7 @@ end function _offseterr() return throw( ArgumentError( - "Offsets are not supported in linear models. You can simply shift the response by the offset.", + "Offsets are not supported in linear models. You can simply shift the response by the offset." ), ) end @@ -372,7 +372,7 @@ function StatsBase.confint(m::MixedModel{T}; level=0.95) where {T} return DictTable(; coef=coefnames(m), lower=β .- cutoff .* std, - upper=β .+ cutoff .* std + upper=β .+ cutoff .* std, ) end @@ -895,7 +895,7 @@ end The penalized, weighted residual sum-of-squares. """ -pwrss(m::LinearMixedModel) = abs2(last(last(m.L))) +pwrss(m::LinearMixedModel{T}) where {T} = abs2(last(last(m.L)))::T """ ranef!(v::Vector{Matrix{T}}, m::MixedModel{T}, β, uscale::Bool) where {T} From ce5b604075d2d1e30ed9860918cbb760ab4220a4 Mon Sep 17 00:00:00 2001 From: Douglas Bates Date: Sat, 22 Jun 2024 10:47:33 -0500 Subject: [PATCH 06/13] use ::Matrix{T} instead of ::T to aid type inference (#773) * use ::Matrix{T} instead of ::T * update NEWS.md * JuliaFormatter run (mostly adding trailing commas). --- NEWS.md | 5 +++++ src/generalizedlinearmixedmodel.jl | 4 ++-- src/likelihoodratiotest.jl | 2 +- src/linalg/logdet.jl | 4 ++-- src/linalg/rankUpdate.jl | 2 +- src/linearmixedmodel.jl | 2 +- src/mixedmodel.jl | 4 ++-- src/predict.jl | 2 +- src/profile/thetapr.jl | 2 +- src/randomeffectsterm.jl | 2 +- src/remat.jl | 4 ++-- src/simulate.jl | 2 +- src/utilities.jl | 2 +- 13 files changed, 21 insertions(+), 16 deletions(-) diff --git a/NEWS.md b/NEWS.md index acf1b91cc..ece040c1a 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,7 @@ +MixedModels v4.24.1 Release Notes +============================== +Add type notations in `pwrss(::LinearMixedModel)` and `logdet(::LinearMixedModel)` to enhance type inference. [#773] + MixedModels v4.24.0 Release Notes ============================== * Properties for `GeneralizedLinearMixedModel` now default to delegation to the internal weighted `LinearMixedModel` when that property is not explicitly handled by `GeneralizedLinearMixedModel`. Previously, properties were delegated on an explicit basis, which meant that they had to be added manually as use cases were discovered. The downside to the new approach is that it is now possible to access properties whose definition in the LMM case doesn't match the GLMM definition when the GLMM definition hasn't been explicitly been implemented. [#767] @@ -521,3 +525,4 @@ Package dependencies [#755]: https://github.com/JuliaStats/MixedModels.jl/issues/755 [#756]: https://github.com/JuliaStats/MixedModels.jl/issues/756 [#767]: https://github.com/JuliaStats/MixedModels.jl/issues/767 +[#773]: https://github.com/JuliaStats/MixedModels.jl/issues/773 diff --git a/src/generalizedlinearmixedmodel.jl b/src/generalizedlinearmixedmodel.jl index f9f6ad5dc..3e2125499 100644 --- a/src/generalizedlinearmixedmodel.jl +++ b/src/generalizedlinearmixedmodel.jl @@ -351,7 +351,7 @@ function GeneralizedLinearMixedModel( tbl, d::Distribution, l::Type; - kwargs... + kwargs..., ) throw(ArgumentError("Expected a Link instance (`$l()`), got a type (`$l`).")) end @@ -376,7 +376,7 @@ function GeneralizedLinearMixedModel( tbl::Tables.ColumnTable, d::Normal, l::IdentityLink; - kwargs... + kwargs..., ) return throw( ArgumentError("use LinearMixedModel for Normal distribution with IdentityLink") diff --git a/src/likelihoodratiotest.jl b/src/likelihoodratiotest.jl index 335cbaa3f..4e2bf7287 100644 --- a/src/likelihoodratiotest.jl +++ b/src/likelihoodratiotest.jl @@ -219,7 +219,7 @@ function _iscomparable(m::LinearMixedModel...) if any(getproperty.(getproperty.(m, :optsum), :REML)) isconstant(coefnames.(m)) || throw( ArgumentError( - "Likelihood-ratio tests for REML-fitted models are only valid when the fixed-effects specifications are identical", + "Likelihood-ratio tests for REML-fitted models are only valid when the fixed-effects specifications are identical" ), ) end diff --git a/src/linalg/logdet.jl b/src/linalg/logdet.jl index 97d637cb5..5f2c5a564 100644 --- a/src/linalg/logdet.jl +++ b/src/linalg/logdet.jl @@ -25,9 +25,9 @@ lower Cholesky factor. """ function LinearAlgebra.logdet(m::LinearMixedModel{T}) where {T} L = m.L - @inbounds s = sum(j -> LD(L[kp1choose2(j)]), axes(m.reterms, 1))::T + @inbounds s = sum(j -> LD(L[kp1choose2(j)])::T, axes(m.reterms, 1)) if m.optsum.REML - lastL = last(L) + lastL = last(L)::Matrix{T} s += LD(lastL) # this includes the log of sqrtpwrss s -= log(last(lastL)) # so we need to subtract it from the sum end diff --git a/src/linalg/rankUpdate.jl b/src/linalg/rankUpdate.jl index e6f1aacd6..705f87d53 100644 --- a/src/linalg/rankUpdate.jl +++ b/src/linalg/rankUpdate.jl @@ -12,7 +12,7 @@ function rankUpdate! end function rankUpdate!(C::AbstractMatrix, a::AbstractArray, α, β) return error( - "We haven't implemented a method for $(typeof(C)), $(typeof(a)). Please file an issue on GitHub.", + "We haven't implemented a method for $(typeof(C)), $(typeof(a)). Please file an issue on GitHub." ) end diff --git a/src/linearmixedmodel.jl b/src/linearmixedmodel.jl index 8ec16f171..875b54c92 100644 --- a/src/linearmixedmodel.jl +++ b/src/linearmixedmodel.jl @@ -895,7 +895,7 @@ end The penalized, weighted residual sum-of-squares. """ -pwrss(m::LinearMixedModel{T}) where {T} = abs2(last(last(m.L)))::T +pwrss(m::LinearMixedModel{T}) where {T} = abs2(last(last(m.L)::Matrix{T})) """ ranef!(v::Vector{Matrix{T}}, m::MixedModel{T}, β, uscale::Bool) where {T} diff --git a/src/mixedmodel.jl b/src/mixedmodel.jl index f57b4c669..3b145f959 100644 --- a/src/mixedmodel.jl +++ b/src/mixedmodel.jl @@ -80,7 +80,7 @@ function StatsAPI.fit( tbl, d::Type, args...; - kwargs... + kwargs..., ) throw(ArgumentError("Expected a Distribution instance (`$d()`), got a type (`$d`).")) end @@ -91,7 +91,7 @@ function StatsAPI.fit( tbl, d::Distribution, l::Type; - kwargs... + kwargs..., ) throw(ArgumentError("Expected a Link instance (`$l()`), got a type (`$l`).")) end diff --git a/src/predict.jl b/src/predict.jl index 5a2246ac6..1cf1c144f 100644 --- a/src/predict.jl +++ b/src/predict.jl @@ -115,7 +115,7 @@ function _predict(m::MixedModel{T}, newdata, β; new_re_levels) where {T} any(any(ismissing, Tables.getcolumn(newdata, col)) for col in respvars) throw( ArgumentError( - "Response column must be initialized to a non-missing numeric value.", + "Response column must be initialized to a non-missing numeric value." ), ) end diff --git a/src/profile/thetapr.jl b/src/profile/thetapr.jl index 62f9473b2..aeb6ebf15 100644 --- a/src/profile/thetapr.jl +++ b/src/profile/thetapr.jl @@ -10,7 +10,7 @@ function optsumj(os::OptSummary, j::Integer) return OptSummary( deleteat!(copy(os.final), j), deleteat!(copy(os.lowerbd), j), - os.optimizer + os.optimizer, ) end diff --git a/src/randomeffectsterm.jl b/src/randomeffectsterm.jl index 432f9af9a..95beee5e7 100644 --- a/src/randomeffectsterm.jl +++ b/src/randomeffectsterm.jl @@ -174,7 +174,7 @@ function StatsModels.apply_schema( if !(typeof(first) <: CategoricalTerm) throw( ArgumentError( - "nesting terms requires categorical grouping term, got $first. Manually specify $first as `CategoricalTerm` in hints/contrasts", + "nesting terms requires categorical grouping term, got $first. Manually specify $first as `CategoricalTerm` in hints/contrasts" ), ) end diff --git a/src/remat.jl b/src/remat.jl index 74d92ff88..ee40c53e6 100644 --- a/src/remat.jl +++ b/src/remat.jl @@ -586,7 +586,7 @@ end function copyscaleinflate!( Ljj::UniformBlockDiagonal{T}, Ajj::UniformBlockDiagonal{T}, - Λj::ReMat{T,S} + Λj::ReMat{T,S}, ) where {T,S} λ = Λj.λ dind = diagind(S, S) @@ -604,7 +604,7 @@ end function copyscaleinflate!( Ljj::Matrix{T}, Ajj::UniformBlockDiagonal{T}, - Λj::ReMat{T,S} + Λj::ReMat{T,S}, ) where {T,S} copyto!(Ljj, Ajj) n = LinearAlgebra.checksquare(Ljj) diff --git a/src/simulate.jl b/src/simulate.jl index 1b4159e1e..9fbeb4ec9 100644 --- a/src/simulate.jl +++ b/src/simulate.jl @@ -236,7 +236,7 @@ function _simulate!( ismissing(σ) || throw( ArgumentError( - "You must not specify a dispersion parameter for model families without a dispersion parameter", + "You must not specify a dispersion parameter for model families without a dispersion parameter" ), ) diff --git a/src/utilities.jl b/src/utilities.jl index 5394a1fe3..413413b7c 100644 --- a/src/utilities.jl +++ b/src/utilities.jl @@ -136,7 +136,7 @@ function replicate( ) use_threads && Base.depwarn( "use_threads is deprecated and will be removed in a future release", - :replicate + :replicate, ) if !isnothing(hide_progress) Base.depwarn( From 34899cf6d95abb2df8c961c9de5a6a500351ebff Mon Sep 17 00:00:00 2001 From: Phillip Alday Date: Tue, 25 Jun 2024 17:27:34 +0000 Subject: [PATCH 07/13] Small performance tweaks (#772) * minor tweaks to improve type inference * another type restriction * fix NEWS and version number * fixes * simplify convenience constructors for OptSummary * fix use of type parameters in defaults * NEWS * tweaks * JuliaFormatter * abstract near-zero checks into configurable params * technically we've added a feature.... --- NEWS.md | 14 ++++- Project.toml | 2 +- src/MixedModels.jl | 2 +- src/generalizedlinearmixedmodel.jl | 4 +- src/linearmixedmodel.jl | 21 ++++---- src/optsummary.jl | 86 ++++++++++++------------------ 6 files changed, 61 insertions(+), 68 deletions(-) diff --git a/NEWS.md b/NEWS.md index ece040c1a..728e40fd7 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,6 +1,16 @@ +MixedModels v4.25 Release Notes +============================== +- Add type notations in `pwrss(::LinearMixedModel)` and `logdet(::LinearMixedModel)` to enhance type inference. [#773] +- Take advantage of type parameter for `StatsAPI.weights(::LinearMixedModel{T})`. [#772] +- Fix use of kwargs in `fit!((::LinearMixedModel)`: [#772] + - user-specified `σ` is actually used, defaulting to existing value + - `REML` defaults to model's already specified REML value. +- Clean up code of keyword convenience constructor for `OptSummary`. [#772] +- Refactor thresholding parameters for forcing near-zero parameter values into `OptSummary`. [#772] + MixedModels v4.24.1 Release Notes ============================== -Add type notations in `pwrss(::LinearMixedModel)` and `logdet(::LinearMixedModel)` to enhance type inference. [#773] +- Re-export accidentally dropped export `lrtest`. [#769] MixedModels v4.24.0 Release Notes ============================== @@ -525,4 +535,6 @@ Package dependencies [#755]: https://github.com/JuliaStats/MixedModels.jl/issues/755 [#756]: https://github.com/JuliaStats/MixedModels.jl/issues/756 [#767]: https://github.com/JuliaStats/MixedModels.jl/issues/767 +[#769]: https://github.com/JuliaStats/MixedModels.jl/issues/769 +[#772]: https://github.com/JuliaStats/MixedModels.jl/issues/772 [#773]: https://github.com/JuliaStats/MixedModels.jl/issues/773 diff --git a/Project.toml b/Project.toml index 6d31df627..9e02e7138 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "MixedModels" uuid = "ff71e718-51f3-5ec2-a782-8ffcbfa3c316" author = ["Phillip Alday ", "Douglas Bates ", "Jose Bayoan Santiago Calderon "] -version = "4.24.1" +version = "4.25.0" [deps] Arrow = "69666777-d1a9-59fb-9406-91d4454c9d45" diff --git a/src/MixedModels.jl b/src/MixedModels.jl index 735b18581..231fdfcc5 100644 --- a/src/MixedModels.jl +++ b/src/MixedModels.jl @@ -19,7 +19,7 @@ using LinearAlgebra: ldiv!, lmul!, logdet, mul!, norm, normalize, normalize!, qr using LinearAlgebra: rank, rdiv!, rmul!, svd, tril! using Markdown: Markdown using MixedModelsDatasets: dataset, datasets -using NLopt: NLopt, Opt, ftol_abs, ftol_rel, initial_step, xtol_abs, xtol_rel +using NLopt: NLopt, Opt using PooledArrays: PooledArrays, PooledArray using PrecompileTools: PrecompileTools, @setup_workload, @compile_workload using ProgressMeter: ProgressMeter, Progress, ProgressUnknown, finish!, next! diff --git a/src/generalizedlinearmixedmodel.jl b/src/generalizedlinearmixedmodel.jl index 3e2125499..cfc06a778 100644 --- a/src/generalizedlinearmixedmodel.jl +++ b/src/generalizedlinearmixedmodel.jl @@ -309,13 +309,13 @@ function StatsAPI.fit!( ## check if very small parameter values bounded below by zero can be set to zero xmin_ = copy(xmin) for i in eachindex(xmin_) - if iszero(optsum.lowerbd[i]) && zero(T) < xmin_[i] < T(0.001) + if iszero(optsum.lowerbd[i]) && zero(T) < xmin_[i] < optsum.xtol_zero_abs xmin_[i] = zero(T) end end loglength = length(fitlog) if xmin ≠ xmin_ - if (zeroobj = obj(xmin_, T[])) ≤ (fmin + 1.e-5) + if (zeroobj = obj(xmin_, T[])) ≤ (fmin + optsum.ftol_zero_abs) fmin = zeroobj copyto!(xmin, xmin_) elseif length(fitlog) > loglength diff --git a/src/linearmixedmodel.jl b/src/linearmixedmodel.jl index 875b54c92..14f297835 100644 --- a/src/linearmixedmodel.jl +++ b/src/linearmixedmodel.jl @@ -36,8 +36,8 @@ struct LinearMixedModel{T<:AbstractFloat} <: MixedModel{T} sqrtwts::Vector{T} parmap::Vector{NTuple{3,Int}} dims::NamedTuple{(:n, :p, :nretrms),NTuple{3,Int}} - A::Vector{AbstractMatrix{T}} # cross-product blocks - L::Vector{AbstractMatrix{T}} + A::Vector{<:AbstractMatrix{T}} # cross-product blocks + L::Vector{<:AbstractMatrix{T}} optsum::OptSummary{T} end @@ -175,7 +175,7 @@ function LinearMixedModel( A, L = createAL(reterms, Xy) lbd = foldl(vcat, lowerbd(c) for c in reterms) θ = foldl(vcat, getθ(c) for c in reterms) - optsum = OptSummary(θ, lbd, :LN_BOBYQA; ftol_rel=T(1.0e-12), ftol_abs=T(1.0e-8)) + optsum = OptSummary(θ, lbd) optsum.sigma = isnothing(σ) ? nothing : T(σ) fill!(optsum.xtol_abs, 1.0e-10) return LinearMixedModel( @@ -408,7 +408,7 @@ function createAL(reterms::Vector{<:AbstractReMat{T}}, Xy::FeMat{T}) where {T} end end end - return A, L + return identity.(A), identity.(L) end StatsAPI.deviance(m::LinearMixedModel) = objective(m) @@ -431,8 +431,8 @@ function feL(m::LinearMixedModel) end """ - fit!(m::LinearMixedModel; progress::Bool=true, REML::Bool=false, - σ::Union{Real, Nothing}=nothing, + fit!(m::LinearMixedModel; progress::Bool=true, REML::Bool=m.optsum.REML, + σ::Union{Real, Nothing}=m.optsum.sigma, thin::Int=typemax(Int)) Optimize the objective of a `LinearMixedModel`. When `progress` is `true` a @@ -445,8 +445,8 @@ saved in `m.optsum.fitlog`. function StatsAPI.fit!( m::LinearMixedModel{T}; progress::Bool=true, - REML::Bool=false, - σ::Union{Real,Nothing}=nothing, + REML::Bool=m.optsum.REML, + σ::Union{Real,Nothing}=m.optsum.sigma, thin::Int=typemax(Int), ) where {T} optsum = m.optsum @@ -461,6 +461,7 @@ function StatsAPI.fit!( end opt = Opt(optsum) optsum.REML = REML + optsum.sigma = σ prog = ProgressUnknown(; desc="Minimizing", showspeed=true) # start from zero for the initial call to obj before optimization iter = 0 @@ -511,13 +512,13 @@ function StatsAPI.fit!( xmin_ = copy(xmin) lb = optsum.lowerbd for i in eachindex(xmin_) - if iszero(lb[i]) && zero(T) < xmin_[i] < T(0.001) + if iszero(lb[i]) && zero(T) < xmin_[i] < optsum.xtol_zero_abs xmin_[i] = zero(T) end end loglength = length(fitlog) if xmin ≠ xmin_ - if (zeroobj = obj(xmin_, T[])) ≤ (fmin + 1.e-5) + if (zeroobj = obj(xmin_, T[])) ≤ (fmin + optsum.ftol_zero_abs) fmin = zeroobj copyto!(xmin, xmin_) elseif length(fitlog) > loglength diff --git a/src/optsummary.jl b/src/optsummary.jl index e79fb4557..2ee69144c 100644 --- a/src/optsummary.jl +++ b/src/optsummary.jl @@ -19,75 +19,55 @@ Summary of an `NLopt` optimization * `feval`: the number of function evaluations * `optimizer`: the name of the optimizer used, as a `Symbol` * `returnvalue`: the return value, as a `Symbol` +* `xtol_zero_abs`: the tolerance for a near zero parameter to be considered practically zero +* `ftol_zero_abs`: the tolerance for change in the objective for setting a near zero parameter to zero +* `fitlog`: A vector of tuples of parameter and objectives values from steps in the optimization * `nAGQ`: number of adaptive Gauss-Hermite quadrature points in deviance evaluation for GLMMs * `REML`: use the REML criterion for LMM fits * `sigma`: a priori value for the residual standard deviation for LMM -* `fitlog`: A vector of tuples of parameter and objectives values from steps in the optimization -The latter four fields are MixedModels functionality and not related directly to the `NLopt` package or algorithms. +The last three fields are MixedModels functionality and not related directly to the `NLopt` package or algorithms. !!! note The internal storage of the parameter values within `fitlog` may change in the future to use a different subtype of `AbstractVector` (e.g., `StaticArrays.SVector`) for each snapshot without being considered a breaking change. """ -mutable struct OptSummary{T<:AbstractFloat} +Base.@kwdef mutable struct OptSummary{T<:AbstractFloat} initial::Vector{T} lowerbd::Vector{T} - finitial::T - ftol_rel::T - ftol_abs::T - xtol_rel::T - xtol_abs::Vector{T} - initial_step::Vector{T} - maxfeval::Int - maxtime::T - feval::Int - final::Vector{T} - fmin::T - optimizer::Symbol - returnvalue::Symbol - nAGQ::Integer # don't really belong here but I needed a place to store them - REML::Bool - sigma::Union{T,Nothing} - fitlog::Vector{Tuple{Vector{T},T}} # not SVector because we would need to parameterize on size (which breaks GLMM) + # the @kwdef macro isn't quite smart enough for us to use the type parameter + # for the default values, but we can fake it + finitial::T = Inf * one(eltype(initial)) + ftol_rel::T = eltype(initial)(1.0e-12) + ftol_abs::T = eltype(initial)(1.0e-8) + xtol_rel::T = zero(eltype(initial)) + xtol_abs::Vector{T} = zero(initial) .+ 1e-10 + initial_step::Vector{T} = empty(initial) + maxfeval::Int = -1 + maxtime::T = -one(eltype(initial)) + feval::Int = -1 + final::Vector{T} = copy(initial) + fmin::T = Inf * one(eltype(initial)) + optimizer::Symbol = :LN_BOBYQA + returnvalue::Symbol = :FAILURE + xtol_zero_abs::T = eltype(initial)(0.001) + ftol_zero_abs::T = eltype(initial)(1.e-5) + # not SVector because we would need to parameterize on size (which breaks GLMM) + fitlog::Vector{Tuple{Vector{T},T}} = [(initial, fmin)] + # don't really belong here but I needed a place to store them + nAGQ::Int = 1 + REML::Bool = false + sigma::Union{T,Nothing} = nothing end function OptSummary( initial::Vector{T}, - lowerbd::Vector{T}, - optimizer::Symbol; - ftol_rel::T=zero(T), - ftol_abs::T=zero(T), - xtol_rel::T=zero(T), - xtol_abs::Vector{T}=zero(initial) .+ 1e-10, - initial_step::Vector{T}=T[], - maxfeval=-1, - maxtime=T(-1), -) where {T<:AbstractFloat} - fitlog = [(initial, T(Inf))] - - return OptSummary( - initial, - lowerbd, - T(Inf), - ftol_rel, - ftol_abs, - xtol_rel, - xtol_abs, - initial_step, - maxfeval, - maxtime, - -1, - copy(initial), - T(Inf), - optimizer, - :FAILURE, - 1, - false, - nothing, - fitlog, - ) + lowerbd::Vector{S}, + optimizer::Symbol=:LN_BOBYQA; kwargs..., +) where {T<:AbstractFloat,S<:AbstractFloat} + TS = promote_type(T, S) + return OptSummary{TS}(; initial, lowerbd, optimizer, kwargs...) end """ From a45fc146d67233aa9d13fb3b0676e1dc1e6d9f37 Mon Sep 17 00:00:00 2001 From: Douglas Bates Date: Thu, 27 Jun 2024 17:26:04 -0500 Subject: [PATCH 08/13] More sophisticated checks in restoreoptsum. (#775) Co-authored-by: Phillip Alday --- .gitignore | 2 + NEWS.md | 5 +++ Project.toml | 2 +- src/MixedModels.jl | 2 + src/serialization.jl | 31 +++++++++++--- test/pls.jl | 100 +++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 134 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index a4fdd21fb..6ce7c9cff 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,5 @@ docs/jmd LocalPreferences.toml benchmark.md +lcov.info +coverage/ diff --git a/NEWS.md b/NEWS.md index 728e40fd7..fa0da0825 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,7 @@ +MixedModels v4.25.1 Release Notes +============================== +- Use more sophisticated checks on property names in `restoreoptsum` to allow for optsums saved by pre-v4.25 versions to be used with this version and later. [#775] + MixedModels v4.25 Release Notes ============================== - Add type notations in `pwrss(::LinearMixedModel)` and `logdet(::LinearMixedModel)` to enhance type inference. [#773] @@ -538,3 +542,4 @@ Package dependencies [#769]: https://github.com/JuliaStats/MixedModels.jl/issues/769 [#772]: https://github.com/JuliaStats/MixedModels.jl/issues/772 [#773]: https://github.com/JuliaStats/MixedModels.jl/issues/773 +[#775]: https://github.com/JuliaStats/MixedModels.jl/issues/775 diff --git a/Project.toml b/Project.toml index 9e02e7138..52e937998 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "MixedModels" uuid = "ff71e718-51f3-5ec2-a782-8ffcbfa3c316" author = ["Phillip Alday ", "Douglas Bates ", "Jose Bayoan Santiago Calderon "] -version = "4.25.0" +version = "4.25.1" [deps] Arrow = "69666777-d1a9-59fb-9406-91d4454c9d45" diff --git a/src/MixedModels.jl b/src/MixedModels.jl index 231fdfcc5..27037facc 100644 --- a/src/MixedModels.jl +++ b/src/MixedModels.jl @@ -205,6 +205,7 @@ include("mimeshow.jl") include("serialization.jl") include("profile/profile.jl") +# COV_EXCL_START @setup_workload begin # Putting some things in `setup` can reduce the size of the # precompile file and potentially make loading faster. @@ -227,5 +228,6 @@ include("profile/profile.jl") progress) end end +# COV_EXCL_STOP end # module diff --git a/src/serialization.jl b/src/serialization.jl index 525a0e55c..52ec1dafe 100644 --- a/src/serialization.jl +++ b/src/serialization.jl @@ -10,11 +10,24 @@ function restoreoptsum!( ) where {T} dict = JSON3.read(io) ops = m.optsum - okay = - (setdiff(propertynames(ops), keys(dict)) == [:lowerbd]) && - all(ops.lowerbd .≤ dict.initial) && - all(ops.lowerbd .≤ dict.final) - if !okay + allowed_missing = ( + :lowerbd, # never saved, -Inf not allowed in JSON + :xtol_zero_abs, # added in v4.25.0 + :ftol_zero_abs, # added in v4.25.0 + :sigma, # added in v4.1.0 + :fitlog, # added in v4.1.0 + ) + nmdiff = setdiff( + propertynames(ops), # names in freshly created optsum + union!(Set(keys(dict)), allowed_missing), # names in saved optsum plus those we allow to be missing + ) + if !isempty(nmdiff) + throw(ArgumentError(string("optsum names: ", nmdiff, " not found in io"))) + end + if length(setdiff(allowed_missing, keys(dict))) > 1 # 1 because :lowerbd + @warn "optsum was saved with an older version of MixedModels.jl: consider resaving." + end + if any(ops.lowerbd .> dict.initial) || any(ops.lowerbd .> dict.final) throw(ArgumentError("initial or final parameters in io do not satisfy lowerbd")) end for fld in (:feval, :finitial, :fmin, :ftol_rel, :ftol_abs, :maxfeval, :nAGQ, :REML) @@ -33,12 +46,16 @@ function restoreoptsum!( end ops.optimizer = Symbol(dict.optimizer) ops.returnvalue = Symbol(dict.returnvalue) - # provides compatibility with fits saved before the introduction of fixed sigma + # compatibility with fits saved before the introduction of various extensions + for prop in [:xtol_zero_abs, :ftol_zero_abs] + fallback = getproperty(ops, prop) + setproperty!(ops, prop, get(dict, prop, fallback)) + end ops.sigma = get(dict, :sigma, nothing) fitlog = get(dict, :fitlog, nothing) ops.fitlog = if isnothing(fitlog) # compat with fits saved before fitlog - [(ops.initial, ops.finitial, ops.final, ops.fmin)] + [(ops.initial, ops.finitial), (ops.final, ops.fmin)] else [(convert(Vector{T}, first(entry)), T(last(entry))) for entry in fitlog] end diff --git a/test/pls.jl b/test/pls.jl index 6dd8e9583..5d39e69b9 100644 --- a/test/pls.jl +++ b/test/pls.jl @@ -543,6 +543,106 @@ end @test loglikelihood(fm) ≈ loglikelihood(m) @test bic(fm) ≈ bic(m) @test coef(fm) ≈ coef(m) + + # check restoreoptsum from older versions + m = LinearMixedModel( + @formula(reaction ~ 1 + days + (1 + days | subj)), + MixedModels.dataset(:sleepstudy), + ) + iob = IOBuffer( +""" +{ + "initial":[1.0,0.0,1.0], + "finitial":1784.642296192436, + "ftol_rel":1.0e-12, + "ftol_abs":1.0e-8, + "xtol_rel":0.0, + "xtol_abs":[1.0e-10,1.0e-10,1.0e-10], + "initial_step":[0.75,1.0,0.75], + "maxfeval":-1, + "maxtime":-1.0, + "feval":57, + "final":[0.9292213195402981,0.01816837807519162,0.22264487477788353], + "fmin":1751.9393444646712, + "optimizer":"LN_BOBYQA", + "returnvalue":"FTOL_REACHED", + "nAGQ":1, + "REML":false +} +""" + ) + @test_logs((:warn, + r"optsum was saved with an older version of MixedModels.jl: consider resaving"), + restoreoptsum!(m, seekstart(iob))) + @test loglikelihood(fm) ≈ loglikelihood(m) + @test bic(fm) ≈ bic(m) + @test coef(fm) ≈ coef(m) + iob = IOBuffer( +""" +{ + "initial":[1.0,0.0,1.0], + "finitial":1784.642296192436, + "ftol_rel":1.0e-12, + "xtol_rel":0.0, + "xtol_abs":[1.0e-10,1.0e-10,1.0e-10], + "initial_step":[0.75,1.0,0.75], + "maxfeval":-1, + "maxtime":-1.0, + "feval":57, + "final":[0.9292213195402981,0.01816837807519162,0.22264487477788353], + "fmin":1751.9393444646712, + "optimizer":"LN_BOBYQA", + "returnvalue":"FTOL_REACHED", + "nAGQ":1, + "REML":false, + "sigma":null, + "fitlog":[[[1.0,0.0,1.0],1784.642296192436]] +} +""" + ) + @test_throws(ArgumentError("optsum names: [:ftol_abs] not found in io"), + restoreoptsum!(m, seekstart(iob))) + + iob = IOBuffer( +""" +{ + "initial":[1.0,0.0,1.0], + "finitial":1784.642296192436, + "ftol_rel":1.0e-12, + "ftol_abs":1.0e-8, + "xtol_rel":0.0, + "xtol_abs":[1.0e-10,1.0e-10,1.0e-10], + "initial_step":[0.75,1.0,0.75], + "maxfeval":-1, + "maxtime":-1.0, + "feval":57, + "final":[-0.9292213195402981,0.01816837807519162,0.22264487477788353], + "fmin":1751.9393444646712, + "optimizer":"LN_BOBYQA", + "returnvalue":"FTOL_REACHED", + "nAGQ":1, + "REML":false, + "sigma":null, + "fitlog":[[[1.0,0.0,1.0],1784.642296192436]] +} +""" + ) + @test_throws(ArgumentError("initial or final parameters in io do not satisfy lowerbd"), + restoreoptsum!(m, seekstart(iob))) + + # make sure new fields are correctly restored + mktemp() do path, io + m = deepcopy(last(models(:sleepstudy))) + m.optsum.xtol_zero_abs = 0.5 + m.optsum.ftol_zero_abs = 0.5 + saveoptsum(io, m) + m.optsum.xtol_zero_abs = 1.0 + m.optsum.ftol_zero_abs = 1.0 + restoreoptsum!(m, seekstart(io)) + @test m.optsum.xtol_zero_abs == 0.5 + @test m.optsum.ftol_zero_abs == 0.5 + end + end @testset "profile" begin From b551a03e78a3963394a250b1d52d8da480e394c5 Mon Sep 17 00:00:00 2001 From: Phillip Alday Date: Wed, 17 Jul 2024 16:21:40 +0000 Subject: [PATCH 09/13] begin supporting `public` keyword (#776) * begin supporting `public` keyword * move dataset[s] to public (was incorrectly exported) * remove qualification from precompile block * suppress some logs in tests * NEWS, version bump * suppress more * BlueStyle --- NEWS.md | 6 ++++++ Project.toml | 4 +++- src/MixedModels.jl | 9 +++++---- test/pls.jl | 6 +++--- test/predict.jl | 4 ++-- 5 files changed, 19 insertions(+), 10 deletions(-) diff --git a/NEWS.md b/NEWS.md index fa0da0825..3c413b95c 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,8 @@ +MixedModels v4.25.2 Release Notes +============================== +- Use `public` keyword so that users don't see unnecessary docstring warnings on 1.11+. [#776] +- Fix accidental export of `dataset` and `datasets` and make them `public` instead. [#776] + MixedModels v4.25.1 Release Notes ============================== - Use more sophisticated checks on property names in `restoreoptsum` to allow for optsums saved by pre-v4.25 versions to be used with this version and later. [#775] @@ -543,3 +548,4 @@ Package dependencies [#772]: https://github.com/JuliaStats/MixedModels.jl/issues/772 [#773]: https://github.com/JuliaStats/MixedModels.jl/issues/773 [#775]: https://github.com/JuliaStats/MixedModels.jl/issues/775 +[#776]: https://github.com/JuliaStats/MixedModels.jl/issues/776 diff --git a/Project.toml b/Project.toml index 52e937998..d66f85475 100644 --- a/Project.toml +++ b/Project.toml @@ -1,11 +1,12 @@ name = "MixedModels" uuid = "ff71e718-51f3-5ec2-a782-8ffcbfa3c316" author = ["Phillip Alday ", "Douglas Bates ", "Jose Bayoan Santiago Calderon "] -version = "4.25.1" +version = "4.25.2" [deps] Arrow = "69666777-d1a9-59fb-9406-91d4454c9d45" BSplineKit = "093aae92-e908-43d7-9660-e50ee39d5a0a" +Compat = "34da2185-b29b-5c13-b0c7-acf172513d20" DataAPI = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a" Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f" GLM = "38e38edf-8417-5370-95a0-9cbb8c7f171a" @@ -33,6 +34,7 @@ TypedTables = "9d95f2ec-7b3d-5a63-8d20-e2491e220bb9" Aqua = "0.8" Arrow = "1, 2" BSplineKit = "0.14, 0.15, 0.16, 0.17" +Compat = "4.10" DataAPI = "1" DataFrames = "1" Distributions = "0.21, 0.22, 0.23, 0.24, 0.25" diff --git a/src/MixedModels.jl b/src/MixedModels.jl index 27037facc..d3b1bddb2 100644 --- a/src/MixedModels.jl +++ b/src/MixedModels.jl @@ -4,6 +4,7 @@ using Arrow: Arrow using Base: Ryu, require_one_based_indexing using BSplineKit: BSplineKit, BSplineOrder, Natural, Derivative, SplineInterpolation using BSplineKit: interpolate +using Compat: @compat using DataAPI: DataAPI, levels, refpool, refarray, refvalue using Distributions: Distributions, Bernoulli, Binomial, Chisq, Distribution, Gamma using Distributions: InverseGaussian, Normal, Poisson, ccdf @@ -89,8 +90,6 @@ export @formula, condVar, condVartables, confint, - dataset, - datasets, deviance, dispersion, dispersion_parameter, @@ -160,6 +159,8 @@ export @formula, # TODO: move this to the correct spot in list once we've decided on name export savereplicates, restorereplicates +@compat public rePCA, PCA, dataset, datasets + """ MixedModel @@ -209,8 +210,8 @@ include("profile/profile.jl") @setup_workload begin # Putting some things in `setup` can reduce the size of the # precompile file and potentially make loading faster. - sleepstudy = MixedModels.dataset(:sleepstudy) - contra = MixedModels.dataset(:contra) + sleepstudy = dataset(:sleepstudy) + contra = dataset(:contra) progress = false @compile_workload begin # all calls in this block will be precompiled, regardless of whether diff --git a/test/pls.jl b/test/pls.jl index 5d39e69b9..c0a540278 100644 --- a/test/pls.jl +++ b/test/pls.jl @@ -628,7 +628,7 @@ end """ ) @test_throws(ArgumentError("initial or final parameters in io do not satisfy lowerbd"), - restoreoptsum!(m, seekstart(iob))) + @suppress restoreoptsum!(m, seekstart(iob))) # make sure new fields are correctly restored mktemp() do path, io @@ -638,7 +638,7 @@ end saveoptsum(io, m) m.optsum.xtol_zero_abs = 1.0 m.optsum.ftol_zero_abs = 1.0 - restoreoptsum!(m, seekstart(io)) + @suppress restoreoptsum!(m, seekstart(io)) @test m.optsum.xtol_zero_abs == 0.5 @test m.optsum.ftol_zero_abs == 0.5 end @@ -646,7 +646,7 @@ end end @testset "profile" begin - pr = profile(last(models(:sleepstudy))) + pr = @suppress profile(last(models(:sleepstudy))) tbl = pr.tbl @test length(tbl) >= 122 ci = confint(pr) diff --git a/test/predict.jl b/test/predict.jl index a55272bbc..8307bd5c7 100644 --- a/test/predict.jl +++ b/test/predict.jl @@ -143,7 +143,7 @@ end slp1 = subset(slp, :days => ByRow(>(0))) # this model probably doesn't make much sense, but it has two # variables on the left hand side in a FunctionTerm - m = fit(MixedModel, @formula(reaction / days ~ 1 + (1|subj)), slp1) + m = @suppress fit(MixedModel, @formula(reaction / days ~ 1 + (1|subj)), slp1) # make sure that we're getting the transformation @test response(m) ≈ slp1.reaction ./ slp1.days @test_throws ArgumentError predict(m, slp[:, Not(:reaction)]) @@ -154,7 +154,7 @@ end @test predict(m, slp1) ≈ fitted(m) - m = fit(MixedModel, @formula(log10(reaction) ~ 1 + days + (1|subj)), slp1) + m = @suppress fit(MixedModel, @formula(log10(reaction) ~ 1 + days + (1|subj)), slp1) # make sure that we're getting the transformation @test response(m) ≈ log10.(slp1.reaction) @test_throws ArgumentError predict(m, slp[:, Not(:reaction)]) From 918457f6aff18a69a307ba7f1b7d1f5601a3003d Mon Sep 17 00:00:00 2001 From: Phillip Alday Date: Fri, 2 Aug 2024 15:06:55 +0000 Subject: [PATCH 10/13] bump minimum tested compat for macOS to Monterey (#779) --- .github/workflows/minimum.yml | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/minimum.yml b/.github/workflows/minimum.yml index f7e37a65f..607edc6be 100644 --- a/.github/workflows/minimum.yml +++ b/.github/workflows/minimum.yml @@ -22,7 +22,7 @@ jobs: matrix: julia-version: [1.8] julia-arch: [x64] - os: [ubuntu-22.04, macos-11, windows-2019] + os: [ubuntu-22.04, macos-12, windows-2019] steps: - uses: actions/checkout@v4 - uses: julia-actions/setup-julia@v2 diff --git a/README.md b/README.md index 148959a1c..faa0846d3 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ Typical distribution forms are _Bernoulli_ for binary data or _Poisson_ for coun |Linux | Ubuntu 20.04 | x64 |v1.8 | |Linux | Ubuntu 20.04 | x64 |current release | |Linux | Ubuntu 20.04 | x64 |nightly | -|macOS | Catalina 10.15| x64 |v1.8 | +|macOS | Monterey 12 | x64 |v1.8 | |Windows | Server 2019 | x64 |v1.8 | Note that previous releases still support older Julia versions. From 19b90aa0384100fa9c3a38db631afbb89287b848 Mon Sep 17 00:00:00 2001 From: Phillip Alday Date: Fri, 2 Aug 2024 17:34:04 +0000 Subject: [PATCH 11/13] rework passing and handling of FE coefficients to `simulate`! for rank deficient models (#778) * rework passing and handling of FE coefficients to `simulate`! for rank deficient models * add test * NEWS * version bump --- NEWS.md | 7 ++++++- Project.toml | 2 +- src/bootstrap.jl | 15 +++++++++------ src/simulate.jl | 34 ++++++++++++++++++---------------- test/bootstrap.jl | 29 ++++++++++++++++++++++++++++- 5 files changed, 62 insertions(+), 25 deletions(-) diff --git a/NEWS.md b/NEWS.md index 3c413b95c..1a53f74ee 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,7 @@ +MixedModels v4.25.3 Release Notes +============================== +- Fix a bug in the handling of rank deficiency in the `simulate[!]` code. This has important correctness implications for bootstrapping models with rank-deficient fixed effects (as can happen in the case of partial crossing of the fixed effects / missing cells). [#778] + MixedModels v4.25.2 Release Notes ============================== - Use `public` keyword so that users don't see unnecessary docstring warnings on 1.11+. [#776] @@ -5,7 +9,7 @@ MixedModels v4.25.2 Release Notes MixedModels v4.25.1 Release Notes ============================== -- Use more sophisticated checks on property names in `restoreoptsum` to allow for optsums saved by pre-v4.25 versions to be used with this version and later. [#775] +- Use more sophisticated checks on property names in `restoreoptsum` to allow for optsums saved by pre-v4.25 versions to be used with this version and later. [#775] MixedModels v4.25 Release Notes ============================== @@ -549,3 +553,4 @@ Package dependencies [#773]: https://github.com/JuliaStats/MixedModels.jl/issues/773 [#775]: https://github.com/JuliaStats/MixedModels.jl/issues/775 [#776]: https://github.com/JuliaStats/MixedModels.jl/issues/776 +[#778]: https://github.com/JuliaStats/MixedModels.jl/issues/778 diff --git a/Project.toml b/Project.toml index d66f85475..122ab02b0 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "MixedModels" uuid = "ff71e718-51f3-5ec2-a782-8ffcbfa3c316" author = ["Phillip Alday ", "Douglas Bates ", "Jose Bayoan Santiago Calderon "] -version = "4.25.2" +version = "4.25.3" [deps] Arrow = "69666777-d1a9-59fb-9406-91d4454c9d45" diff --git a/src/bootstrap.jl b/src/bootstrap.jl index 269c5567f..c90dc33a7 100644 --- a/src/bootstrap.jl +++ b/src/bootstrap.jl @@ -177,7 +177,7 @@ end """ parametricbootstrap([rng::AbstractRNG], nsamp::Integer, m::MixedModel{T}, ftype=T; - β = coef(m), σ = m.σ, θ = m.θ, progress=true, optsum_overrides=(;)) + β = fixef(m), σ = m.σ, θ = m.θ, progress=true, optsum_overrides=(;)) Perform `nsamp` parametric bootstrap replication fits of `m`, returning a `MixedModelBootstrap`. @@ -214,7 +214,7 @@ function parametricbootstrap( n::Integer, morig::MixedModel{T}, ftype::Type{<:AbstractFloat}=T; - β::AbstractVector=coef(morig), + β::AbstractVector=fixef(morig), σ=morig.σ, θ::AbstractVector=morig.θ, use_threads::Bool=false, @@ -232,9 +232,13 @@ function parametricbootstrap( if σ !== missing σ = T(σ) end - β, θ = convert(Vector{T}, β), convert(Vector{T}, θ) - βsc, θsc = similar(ftype.(β)), similar(ftype.(θ)) - p, k = length(β), length(θ) + β = convert(Vector{T}, β) + θ = convert(Vector{T}, θ) + # scratch -- note that this is the length of the unpivoted coef vector + βsc = coef(morig) + θsc = zeros(ftype, length(θ)) + p = length(βsc) + k = length(θsc) m = deepcopy(morig) for (key, val) in pairs(optsum_overrides) setfield!(m.optsum, key, val) @@ -251,7 +255,6 @@ function parametricbootstrap( samp = replicate(n; progress) do simulate!(rng, m; β, σ, θ) refit!(m; progress=false) - # @info "" m.optsum.feval ( objective=ftype.(m.objective), σ=ismissing(m.σ) ? missing : ftype(m.σ), diff --git a/src/simulate.jl b/src/simulate.jl index 9fbeb4ec9..035a8c02c 100644 --- a/src/simulate.jl +++ b/src/simulate.jl @@ -18,13 +18,17 @@ function simulate(m::MixedModel, args...; kwargs...) end """ - simulate!(rng::AbstractRNG, m::MixedModel{T}; β=m.β, σ=m.σ, θ=T[]) - simulate!(m::MixedModel; β=m.β, σ=m.σ, θ=m.θ) + simulate!(rng::AbstractRNG, m::MixedModel{T}; β=fixef(m), σ=m.σ, θ=T[]) + simulate!(m::MixedModel; β=fixef(m), σ=m.σ, θ=m.θ) Overwrite the response (i.e. `m.trms[end]`) with a simulated response vector from model `m`. This simulation includes sampling new values for the random effects. +`β` can be specified either as a pivoted, full rank coefficient vector (cf. [`fixef`](@ref)) +or as an unpivoted full dimension coefficient vector (cf. [`coef`](@ref)), where the entries +corresponding to redundant columns will be ignored. + !!! note Note that `simulate!` methods with a `y::AbstractVector` as the first argument (besides the RNG) and `simulate` methods return the simulated response. This is @@ -32,7 +36,7 @@ This simulation includes sampling new values for the random effects. which modify the model's response and return the entire modified model. """ function simulate!( - rng::AbstractRNG, m::LinearMixedModel{T}; β=coef(m), σ=m.σ, θ=T[] + rng::AbstractRNG, m::LinearMixedModel{T}; β=fixef(m), σ=m.σ, θ=T[] ) where {T} # XXX should we add support for doing something with weights? simulate!(rng, m.y, m; β, σ, θ) @@ -40,7 +44,7 @@ function simulate!( end function simulate!( - rng::AbstractRNG, m::GeneralizedLinearMixedModel{T}; β=coef(m), σ=m.σ, θ=T[] + rng::AbstractRNG, m::GeneralizedLinearMixedModel{T}; β=fixef(m), σ=m.σ, θ=T[] ) where {T} # note that these m.resp.y and m.LMM.y will later be synchronized in (re)fit!() # but for now we use them as distinct scratch buffers to avoid allocations @@ -85,7 +89,7 @@ function _rand(rng::AbstractRNG, d::Distribution, location, scale=NaN, n=1) return rand(rng, dist) / n end -function simulate!(m::MixedModel{T}; β=coef(m), σ=m.σ, θ=T[]) where {T} +function simulate!(m::MixedModel{T}; β=fixef(m), σ=m.σ, θ=T[]) where {T} return simulate!(Random.GLOBAL_RNG, m; β, σ, θ) end @@ -121,7 +125,7 @@ function simulate!( y::AbstractVector, m::LinearMixedModel, newdata::Tables.ColumnTable; - β=m.β, + β=fixef(m), σ=m.σ, θ=m.θ, ) @@ -147,9 +151,9 @@ function simulate!( end function simulate!( - rng::AbstractRNG, y::AbstractVector, m::LinearMixedModel{T}; β=m.β, σ=m.σ, θ=m.θ + rng::AbstractRNG, y::AbstractVector, m::LinearMixedModel{T}; β=fixef(m), σ=m.σ, θ=m.θ ) where {T} - length(β) == length(pivot(m)) || length(β) == m.feterm.rank || + length(β) == length(pivot(m)) || length(β) == rank(m) || throw(ArgumentError("You must specify all (non-singular) βs")) β = convert(Vector{T}, β) @@ -157,10 +161,8 @@ function simulate!( θ = convert(Vector{T}, θ) isempty(θ) || setθ!(m, θ) - if length(β) ≠ length(pivot(m)) - padding = length(pivot(m)) - rank(m) - append!(β, fill(-0.0, padding)) - invpermute!(β, pivot(m)) + if length(β) == length(pivot(m)) + β = view(view(β, pivot(m)), 1:rank(m)) end # initialize y to standard normal @@ -172,7 +174,7 @@ function simulate!( end # scale by σ and add fixed-effects contribution - return mul!(y, m.X, β, one(T), σ) + return mul!(y, fullrankx(m), β, one(T), σ) end function simulate!( @@ -180,7 +182,7 @@ function simulate!( y::AbstractVector, m::GeneralizedLinearMixedModel, newdata::Tables.ColumnTable; - β=m.β, + β=fixef(m), σ=m.σ, θ=m.θ, ) @@ -209,7 +211,7 @@ function simulate!( rng::AbstractRNG, y::AbstractVector, m::GeneralizedLinearMixedModel{T}; - β=m.β, + β=fixef(m), σ=m.σ, θ=m.θ, ) where {T} @@ -250,7 +252,7 @@ function _simulate!( if length(β) == length(pivot(m)) # unlike LMM, GLMM stores the truncated, pivoted vector directly - β = view(β, view(pivot(m), 1:(rank(m)))) + β = view(view(β, pivot(m)), 1:rank(m)) end fast = (length(m.θ) == length(m.optsum.final)) setpar! = fast ? setθ! : setβθ! diff --git a/test/bootstrap.jl b/test/bootstrap.jl index 576aad918..49c28441f 100644 --- a/test/bootstrap.jl +++ b/test/bootstrap.jl @@ -226,7 +226,7 @@ end rng = MersenneTwister(0); x = rand(rng, 100); data = (x = x, x2 = 1.5 .* x, y = rand(rng, [0,1], 100), z = repeat('A':'T', 5)) - @testset "$family" for family in [Normal(), Bernoulli()] + @testset "$family" for family in [Normal(), Bernoulli()] model = @suppress fit(MixedModel, @formula(y ~ x + x2 + (1|z)), data, family; progress=false) boot = quickboot(model, 10) @@ -242,6 +242,33 @@ end yf = simulate(StableRNG(1), model; β=fixef(model)) @test all(x -> isapprox(x...), zip(yc, yf)) end + + @testset "partial crossing" begin + id = lpad.(string.(1:40), 2, "0") + B = ["b0", "b1", "b2"] + C = ["c0", "c1", "c2", "c3", "c4"] + df = DataFrame(reshape(collect(Iterators.product(B, C, id)), :), [:b, :c, :id]) + df[!, :y] .= 0 + filter!(df) do row + b = last(row.b) + c = last(row.c) + return b != c + end + + m = LinearMixedModel(@formula(y ~ 1 + b * c + (1|id)), df) + β = 1:rank(m) + σ = 1 + simulate!(StableRNG(628), m; β, σ) + fit!(m) + + boot = parametricbootstrap(StableRNG(271828), 1000, m); + bootci = DataFrame(shortestcovint(boot)) + filter!(:group => ismissing, bootci) + select!(bootci, :names => disallowmissing => :coef, :lower, :upper) + transform!(bootci, [:lower, :upper] => ByRow(middle) => :mean) + + @test all(x -> isapprox(x[1], x[2]; atol=0.1), zip(coef(m), bootci.mean)) + end end end From 911a07a10a1600c8ddd86d7abe89832724b94b73 Mon Sep 17 00:00:00 2001 From: Phillip Alday Date: Wed, 14 Aug 2024 14:40:18 +0000 Subject: [PATCH 12/13] tracking down non covergence in Issue 780 (#781) * tracking down non covergence in Issue 780 * init * other tinkerings * notes --- issues/780/Manifest.toml | 836 +++++++++++++++++++++++++++++++++++++++ issues/780/Project.toml | 10 + issues/780/issue.jl | 120 ++++++ 3 files changed, 966 insertions(+) create mode 100644 issues/780/Manifest.toml create mode 100644 issues/780/Project.toml create mode 100644 issues/780/issue.jl diff --git a/issues/780/Manifest.toml b/issues/780/Manifest.toml new file mode 100644 index 000000000..117b80340 --- /dev/null +++ b/issues/780/Manifest.toml @@ -0,0 +1,836 @@ +# This file is machine-generated - editing it directly is not advised + +julia_version = "1.10.4" +manifest_format = "2.0" +project_hash = "ee9452c19ab51ba0816b484826fde7c9c38fea0f" + +[[deps.Adapt]] +deps = ["LinearAlgebra", "Requires"] +git-tree-sha1 = "6a55b747d1812e699320963ffde36f1ebdda4099" +uuid = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" +version = "4.0.4" +weakdeps = ["StaticArrays"] + + [deps.Adapt.extensions] + AdaptStaticArraysExt = "StaticArrays" + +[[deps.AliasTables]] +deps = ["PtrArrays", "Random"] +git-tree-sha1 = "9876e1e164b144ca45e9e3198d0b689cadfed9ff" +uuid = "66dad0bd-aa9a-41b7-9441-69ab47430ed8" +version = "1.1.3" + +[[deps.ArgTools]] +uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f" +version = "1.1.1" + +[[deps.ArrayLayouts]] +deps = ["FillArrays", "LinearAlgebra"] +git-tree-sha1 = "ce2ca959f932f5dad70697dd93133d1167cf1e4e" +uuid = "4c555306-a7a7-4459-81d9-ec55ddd5c99a" +version = "1.10.2" +weakdeps = ["SparseArrays"] + + [deps.ArrayLayouts.extensions] + ArrayLayoutsSparseArraysExt = "SparseArrays" + +[[deps.Arrow]] +deps = ["ArrowTypes", "BitIntegers", "CodecLz4", "CodecZstd", "ConcurrentUtilities", "DataAPI", "Dates", "EnumX", "LoggingExtras", "Mmap", "PooledArrays", "SentinelArrays", "Tables", "TimeZones", "TranscodingStreams", "UUIDs"] +git-tree-sha1 = "f8d411d1b45459368567dc51f683ed78a919d795" +uuid = "69666777-d1a9-59fb-9406-91d4454c9d45" +version = "2.7.2" + +[[deps.ArrowTypes]] +deps = ["Sockets", "UUIDs"] +git-tree-sha1 = "404265cd8128a2515a81d5eae16de90fdef05101" +uuid = "31f734f8-188a-4ce0-8406-c8a06bd891cd" +version = "2.3.0" + +[[deps.Artifacts]] +uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" + +[[deps.BSplineKit]] +deps = ["ArrayLayouts", "BandedMatrices", "FastGaussQuadrature", "ForwardDiff", "LinearAlgebra", "PrecompileTools", "Random", "Reexport", "SparseArrays", "Static", "StaticArrays", "StaticArraysCore"] +git-tree-sha1 = "79dba2b0d60f225f4660075cb0e9b4da9960042a" +uuid = "093aae92-e908-43d7-9660-e50ee39d5a0a" +version = "0.17.6" + +[[deps.BandedMatrices]] +deps = ["ArrayLayouts", "FillArrays", "LinearAlgebra", "PrecompileTools"] +git-tree-sha1 = "71f605effb24081b09cae943ba39ef9ca90c04f4" +uuid = "aae01518-5342-5314-be14-df237901396f" +version = "1.7.2" +weakdeps = ["SparseArrays"] + + [deps.BandedMatrices.extensions] + BandedMatricesSparseArraysExt = "SparseArrays" + +[[deps.Base64]] +uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" + +[[deps.BitIntegers]] +deps = ["Random"] +git-tree-sha1 = "a55462dfddabc34bc97d3a7403a2ca2802179ae6" +uuid = "c3b6d118-76ef-56ca-8cc7-ebb389d030a1" +version = "0.3.1" + +[[deps.CSV]] +deps = ["CodecZlib", "Dates", "FilePathsBase", "InlineStrings", "Mmap", "Parsers", "PooledArrays", "PrecompileTools", "SentinelArrays", "Tables", "Unicode", "WeakRefStrings", "WorkerUtilities"] +git-tree-sha1 = "6c834533dc1fabd820c1db03c839bf97e45a3fab" +uuid = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" +version = "0.10.14" + +[[deps.CodecLz4]] +deps = ["Lz4_jll", "TranscodingStreams"] +git-tree-sha1 = "0db0c70ca94c0a79cadad269497f25ca88b9fa91" +uuid = "5ba52731-8f18-5e0d-9241-30f10d1ec561" +version = "0.4.5" + +[[deps.CodecZlib]] +deps = ["TranscodingStreams", "Zlib_jll"] +git-tree-sha1 = "bce6804e5e6044c6daab27bb533d1295e4a2e759" +uuid = "944b1d66-785c-5afd-91f1-9de20f533193" +version = "0.7.6" + +[[deps.CodecZstd]] +deps = ["TranscodingStreams", "Zstd_jll"] +git-tree-sha1 = "5e41a52bec3b0881a7eb54f5391b779994504186" +uuid = "6b39b394-51ab-5f42-8807-6242bab2b4c2" +version = "0.8.5" + +[[deps.CommonSubexpressions]] +deps = ["MacroTools", "Test"] +git-tree-sha1 = "7b8a93dba8af7e3b42fecabf646260105ac373f7" +uuid = "bbf7d656-a473-5ed7-a52c-81e309532950" +version = "0.3.0" + +[[deps.CommonWorldInvalidations]] +git-tree-sha1 = "ae52d1c52048455e85a387fbee9be553ec2b68d0" +uuid = "f70d9fcc-98c5-4d4a-abd7-e4cdeebd8ca8" +version = "1.0.0" + +[[deps.Compat]] +deps = ["TOML", "UUIDs"] +git-tree-sha1 = "8ae8d32e09f0dcf42a36b90d4e17f5dd2e4c4215" +uuid = "34da2185-b29b-5c13-b0c7-acf172513d20" +version = "4.16.0" +weakdeps = ["Dates", "LinearAlgebra"] + + [deps.Compat.extensions] + CompatLinearAlgebraExt = "LinearAlgebra" + +[[deps.CompilerSupportLibraries_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae" +version = "1.1.1+0" + +[[deps.ConcurrentUtilities]] +deps = ["Serialization", "Sockets"] +git-tree-sha1 = "ea32b83ca4fefa1768dc84e504cc0a94fb1ab8d1" +uuid = "f0e56b4a-5159-44fe-b623-3e5288b988bb" +version = "2.4.2" + +[[deps.Crayons]] +git-tree-sha1 = "249fe38abf76d48563e2f4556bebd215aa317e15" +uuid = "a8cc5b0e-0ffa-5ad4-8c14-923d3ee1735f" +version = "4.1.1" + +[[deps.DataAPI]] +git-tree-sha1 = "abe83f3a2f1b857aac70ef8b269080af17764bbe" +uuid = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a" +version = "1.16.0" + +[[deps.DataFrames]] +deps = ["Compat", "DataAPI", "DataStructures", "Future", "InlineStrings", "InvertedIndices", "IteratorInterfaceExtensions", "LinearAlgebra", "Markdown", "Missings", "PooledArrays", "PrecompileTools", "PrettyTables", "Printf", "REPL", "Random", "Reexport", "SentinelArrays", "SortingAlgorithms", "Statistics", "TableTraits", "Tables", "Unicode"] +git-tree-sha1 = "04c738083f29f86e62c8afc341f0967d8717bdb8" +uuid = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" +version = "1.6.1" + +[[deps.DataStructures]] +deps = ["Compat", "InteractiveUtils", "OrderedCollections"] +git-tree-sha1 = "1d0a14036acb104d9e89698bd408f63ab58cdc82" +uuid = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" +version = "0.18.20" + +[[deps.DataValueInterfaces]] +git-tree-sha1 = "bfc1187b79289637fa0ef6d4436ebdfe6905cbd6" +uuid = "e2d170a0-9d28-54be-80f0-106bbe20a464" +version = "1.0.0" + +[[deps.Dates]] +deps = ["Printf"] +uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" + +[[deps.Dictionaries]] +deps = ["Indexing", "Random", "Serialization"] +git-tree-sha1 = "35b66b6744b2d92c778afd3a88d2571875664a2a" +uuid = "85a47980-9c8c-11e8-2b9f-f7ca1fa99fb4" +version = "0.4.2" + +[[deps.DiffResults]] +deps = ["StaticArraysCore"] +git-tree-sha1 = "782dd5f4561f5d267313f23853baaaa4c52ea621" +uuid = "163ba53b-c6d8-5494-b064-1a9d43ac40c5" +version = "1.1.0" + +[[deps.DiffRules]] +deps = ["IrrationalConstants", "LogExpFunctions", "NaNMath", "Random", "SpecialFunctions"] +git-tree-sha1 = "23163d55f885173722d1e4cf0f6110cdbaf7e272" +uuid = "b552c78f-8df3-52c6-915a-8e097449b14b" +version = "1.15.1" + +[[deps.Distributed]] +deps = ["Random", "Serialization", "Sockets"] +uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b" + +[[deps.Distributions]] +deps = ["AliasTables", "FillArrays", "LinearAlgebra", "PDMats", "Printf", "QuadGK", "Random", "SpecialFunctions", "Statistics", "StatsAPI", "StatsBase", "StatsFuns"] +git-tree-sha1 = "0e0a1264b0942f1f3abb2b30891f2a590cc652ac" +uuid = "31c24e10-a181-5473-b8eb-7969acd0382f" +version = "0.25.110" + + [deps.Distributions.extensions] + DistributionsChainRulesCoreExt = "ChainRulesCore" + DistributionsDensityInterfaceExt = "DensityInterface" + DistributionsTestExt = "Test" + + [deps.Distributions.weakdeps] + ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" + DensityInterface = "b429d917-457f-4dbc-8f4c-0cc954292b1d" + Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[[deps.DocStringExtensions]] +deps = ["LibGit2"] +git-tree-sha1 = "2fb1e02f2b635d0845df5d7c167fec4dd739b00d" +uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" +version = "0.9.3" + +[[deps.Downloads]] +deps = ["ArgTools", "FileWatching", "LibCURL", "NetworkOptions"] +uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6" +version = "1.6.0" + +[[deps.EnumX]] +git-tree-sha1 = "bdb1942cd4c45e3c678fd11569d5cccd80976237" +uuid = "4e289a0a-7415-4d19-859d-a7e5c4648b56" +version = "1.0.4" + +[[deps.ExprTools]] +git-tree-sha1 = "27415f162e6028e81c72b82ef756bf321213b6ec" +uuid = "e2ba6199-217a-4e67-a87a-7c52f15ade04" +version = "0.1.10" + +[[deps.FastGaussQuadrature]] +deps = ["LinearAlgebra", "SpecialFunctions", "StaticArrays"] +git-tree-sha1 = "fd923962364b645f3719855c88f7074413a6ad92" +uuid = "442a2c76-b920-505d-bb47-c5924d526838" +version = "1.0.2" + +[[deps.FilePathsBase]] +deps = ["Compat", "Dates", "Mmap", "Printf", "Test", "UUIDs"] +git-tree-sha1 = "9f00e42f8d99fdde64d40c8ea5d14269a2e2c1aa" +uuid = "48062228-2e41-5def-b9a4-89aafe57970f" +version = "0.9.21" + +[[deps.FileWatching]] +uuid = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee" + +[[deps.FillArrays]] +deps = ["LinearAlgebra"] +git-tree-sha1 = "0653c0a2396a6da5bc4766c43041ef5fd3efbe57" +uuid = "1a297f60-69ca-5386-bcde-b61e274b549b" +version = "1.11.0" +weakdeps = ["PDMats", "SparseArrays", "Statistics"] + + [deps.FillArrays.extensions] + FillArraysPDMatsExt = "PDMats" + FillArraysSparseArraysExt = "SparseArrays" + FillArraysStatisticsExt = "Statistics" + +[[deps.ForwardDiff]] +deps = ["CommonSubexpressions", "DiffResults", "DiffRules", "LinearAlgebra", "LogExpFunctions", "NaNMath", "Preferences", "Printf", "Random", "SpecialFunctions"] +git-tree-sha1 = "cf0fe81336da9fb90944683b8c41984b08793dad" +uuid = "f6369f11-7733-5829-9624-2563aa707210" +version = "0.10.36" +weakdeps = ["StaticArrays"] + + [deps.ForwardDiff.extensions] + ForwardDiffStaticArraysExt = "StaticArrays" + +[[deps.Future]] +deps = ["Random"] +uuid = "9fa8497b-333b-5362-9e8d-4d0656e87820" + +[[deps.GLM]] +deps = ["Distributions", "LinearAlgebra", "Printf", "Reexport", "SparseArrays", "SpecialFunctions", "Statistics", "StatsAPI", "StatsBase", "StatsFuns", "StatsModels"] +git-tree-sha1 = "273bd1cd30768a2fddfa3fd63bbc746ed7249e5f" +uuid = "38e38edf-8417-5370-95a0-9cbb8c7f171a" +version = "1.9.0" + +[[deps.HypergeometricFunctions]] +deps = ["LinearAlgebra", "OpenLibm_jll", "SpecialFunctions"] +git-tree-sha1 = "7c4195be1649ae622304031ed46a2f4df989f1eb" +uuid = "34004b35-14d8-5ef3-9330-4cdb6864b03a" +version = "0.3.24" + +[[deps.IfElse]] +git-tree-sha1 = "debdd00ffef04665ccbb3e150747a77560e8fad1" +uuid = "615f187c-cbe4-4ef1-ba3b-2fcf58d6d173" +version = "0.1.1" + +[[deps.Indexing]] +git-tree-sha1 = "ce1566720fd6b19ff3411404d4b977acd4814f9f" +uuid = "313cdc1a-70c2-5d6a-ae34-0150d3930a38" +version = "1.1.1" + +[[deps.InlineStrings]] +git-tree-sha1 = "45521d31238e87ee9f9732561bfee12d4eebd52d" +uuid = "842dd82b-1e85-43dc-bf29-5d0ee9dffc48" +version = "1.4.2" +weakdeps = ["ArrowTypes", "Parsers"] + + [deps.InlineStrings.extensions] + ArrowTypesExt = "ArrowTypes" + ParsersExt = "Parsers" + +[[deps.InteractiveUtils]] +deps = ["Markdown"] +uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" + +[[deps.InvertedIndices]] +git-tree-sha1 = "0dc7b50b8d436461be01300fd8cd45aa0274b038" +uuid = "41ab1584-1d38-5bbf-9106-f11c6c58b48f" +version = "1.3.0" + +[[deps.IrrationalConstants]] +git-tree-sha1 = "630b497eafcc20001bba38a4651b327dcfc491d2" +uuid = "92d709cd-6900-40b7-9082-c6be49f344b6" +version = "0.2.2" + +[[deps.IteratorInterfaceExtensions]] +git-tree-sha1 = "a3f24677c21f5bbe9d2a714f95dcd58337fb2856" +uuid = "82899510-4779-5014-852e-03e436cf321d" +version = "1.0.0" + +[[deps.JLLWrappers]] +deps = ["Artifacts", "Preferences"] +git-tree-sha1 = "7e5d6779a1e09a36db2a7b6cff50942a0a7d0fca" +uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210" +version = "1.5.0" + +[[deps.JSON3]] +deps = ["Dates", "Mmap", "Parsers", "PrecompileTools", "StructTypes", "UUIDs"] +git-tree-sha1 = "eb3edce0ed4fa32f75a0a11217433c31d56bd48b" +uuid = "0f8b85d8-7281-11e9-16c2-39a750bddbf1" +version = "1.14.0" +weakdeps = ["ArrowTypes"] + + [deps.JSON3.extensions] + JSON3ArrowExt = ["ArrowTypes"] + +[[deps.LaTeXStrings]] +git-tree-sha1 = "50901ebc375ed41dbf8058da26f9de442febbbec" +uuid = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f" +version = "1.3.1" + +[[deps.LazyArtifacts]] +deps = ["Artifacts", "Pkg"] +uuid = "4af54fe1-eca0-43a8-85a7-787d91b784e3" + +[[deps.LibCURL]] +deps = ["LibCURL_jll", "MozillaCACerts_jll"] +uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21" +version = "0.6.4" + +[[deps.LibCURL_jll]] +deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"] +uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0" +version = "8.4.0+0" + +[[deps.LibGit2]] +deps = ["Base64", "LibGit2_jll", "NetworkOptions", "Printf", "SHA"] +uuid = "76f85450-5226-5b5a-8eaa-529ad045b433" + +[[deps.LibGit2_jll]] +deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll"] +uuid = "e37daf67-58a4-590a-8e99-b0245dd2ffc5" +version = "1.6.4+0" + +[[deps.LibSSH2_jll]] +deps = ["Artifacts", "Libdl", "MbedTLS_jll"] +uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8" +version = "1.11.0+1" + +[[deps.Libdl]] +uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" + +[[deps.LinearAlgebra]] +deps = ["Libdl", "OpenBLAS_jll", "libblastrampoline_jll"] +uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" + +[[deps.LogExpFunctions]] +deps = ["DocStringExtensions", "IrrationalConstants", "LinearAlgebra"] +git-tree-sha1 = "a2d09619db4e765091ee5c6ffe8872849de0feea" +uuid = "2ab3a3ac-af41-5b50-aa03-7779005ae688" +version = "0.3.28" + + [deps.LogExpFunctions.extensions] + LogExpFunctionsChainRulesCoreExt = "ChainRulesCore" + LogExpFunctionsChangesOfVariablesExt = "ChangesOfVariables" + LogExpFunctionsInverseFunctionsExt = "InverseFunctions" + + [deps.LogExpFunctions.weakdeps] + ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" + ChangesOfVariables = "9e997f8a-9a97-42d5-a9f1-ce6bfc15e2c0" + InverseFunctions = "3587e190-3f89-42d0-90ee-14403ec27112" + +[[deps.Logging]] +uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" + +[[deps.LoggingExtras]] +deps = ["Dates", "Logging"] +git-tree-sha1 = "c1dd6d7978c12545b4179fb6153b9250c96b0075" +uuid = "e6f89c97-d47a-5376-807f-9c37f3926c36" +version = "1.0.3" + +[[deps.Lz4_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "7f26c8fc5229e68484e0b3447312c98e16207d11" +uuid = "5ced341a-0733-55b8-9ab6-a4889d929147" +version = "1.10.0+0" + +[[deps.MacroTools]] +deps = ["Markdown", "Random"] +git-tree-sha1 = "2fa9ee3e63fd3a4f7a9a4f4744a52f4856de82df" +uuid = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" +version = "0.5.13" + +[[deps.Markdown]] +deps = ["Base64"] +uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" + +[[deps.MbedTLS_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" +version = "2.28.2+1" + +[[deps.Missings]] +deps = ["DataAPI"] +git-tree-sha1 = "ec4f7fbeab05d7747bdf98eb74d130a2a2ed298d" +uuid = "e1d29d7a-bbdc-5cf2-9ac0-f12de2c33e28" +version = "1.2.0" + +[[deps.MixedModels]] +deps = ["Arrow", "BSplineKit", "Compat", "DataAPI", "Distributions", "GLM", "JSON3", "LinearAlgebra", "Markdown", "MixedModelsDatasets", "NLopt", "PooledArrays", "PrecompileTools", "ProgressMeter", "Random", "SparseArrays", "StaticArrays", "Statistics", "StatsAPI", "StatsBase", "StatsFuns", "StatsModels", "StructTypes", "Tables", "TypedTables"] +git-tree-sha1 = "55b9364f382b37c0794d7e8065aefceaa225c04c" +uuid = "ff71e718-51f3-5ec2-a782-8ffcbfa3c316" +version = "4.25.3" + +[[deps.MixedModelsDatasets]] +deps = ["Arrow", "Artifacts", "LazyArtifacts"] +git-tree-sha1 = "5f508af97ecf39645febed8ba2fabf5cfdc682e0" +uuid = "7e9fb7ac-9f67-43bf-b2c8-96ba0796cbb6" +version = "0.1.1" + +[[deps.Mmap]] +uuid = "a63ad114-7e13-5084-954f-fe012c677804" + +[[deps.Mocking]] +deps = ["Compat", "ExprTools"] +git-tree-sha1 = "ead0dbb33b6808578c385ffaab20d9b57053661b" +uuid = "78c3b35d-d492-501b-9361-3d52fe80e533" +version = "0.8.0" + +[[deps.MozillaCACerts_jll]] +uuid = "14a3606d-f60d-562e-9121-12d972cd8159" +version = "2023.1.10" + +[[deps.NLopt]] +deps = ["NLopt_jll"] +git-tree-sha1 = "3b887e2ef56be3309e68d2546c6178e2d2fa9a60" +uuid = "76087f3c-5699-56af-9a33-bf431cd00edd" +version = "1.0.2" + + [deps.NLopt.extensions] + NLoptMathOptInterfaceExt = ["MathOptInterface"] + + [deps.NLopt.weakdeps] + MathOptInterface = "b8f27783-ece8-5eb3-8dc8-9495eed66fee" + +[[deps.NLopt_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "3d1eefa627faeabc59ab9edbf00d17f70123ad69" +uuid = "079eb43e-fd8e-5478-9966-2cf3e3edb778" +version = "2.8.0+0" + +[[deps.NaNMath]] +deps = ["OpenLibm_jll"] +git-tree-sha1 = "0877504529a3e5c3343c6f8b4c0381e57e4387e4" +uuid = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3" +version = "1.0.2" + +[[deps.NetworkOptions]] +uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" +version = "1.2.0" + +[[deps.OpenBLAS_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"] +uuid = "4536629a-c528-5b80-bd46-f80d51c5b363" +version = "0.3.23+4" + +[[deps.OpenLibm_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "05823500-19ac-5b8b-9628-191a04bc5112" +version = "0.8.1+2" + +[[deps.OpenSpecFun_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "13652491f6856acfd2db29360e1bbcd4565d04f1" +uuid = "efe28fd5-8261-553b-a9e1-b2916fc3738e" +version = "0.5.5+0" + +[[deps.OrderedCollections]] +git-tree-sha1 = "dfdf5519f235516220579f949664f1bf44e741c5" +uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" +version = "1.6.3" + +[[deps.PDMats]] +deps = ["LinearAlgebra", "SparseArrays", "SuiteSparse"] +git-tree-sha1 = "949347156c25054de2db3b166c52ac4728cbad65" +uuid = "90014a1f-27ba-587c-ab20-58faa44d9150" +version = "0.11.31" + +[[deps.Parsers]] +deps = ["Dates", "PrecompileTools", "UUIDs"] +git-tree-sha1 = "8489905bcdbcfac64d1daa51ca07c0d8f0283821" +uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" +version = "2.8.1" + +[[deps.Pkg]] +deps = ["Artifacts", "Dates", "Downloads", "FileWatching", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"] +uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" +version = "1.10.0" + +[[deps.PooledArrays]] +deps = ["DataAPI", "Future"] +git-tree-sha1 = "36d8b4b899628fb92c2749eb488d884a926614d3" +uuid = "2dfb63ee-cc39-5dd5-95bd-886bf059d720" +version = "1.4.3" + +[[deps.PrecompileTools]] +deps = ["Preferences"] +git-tree-sha1 = "5aa36f7049a63a1528fe8f7c3f2113413ffd4e1f" +uuid = "aea7be01-6a6a-4083-8856-8a6e6704d82a" +version = "1.2.1" + +[[deps.Preferences]] +deps = ["TOML"] +git-tree-sha1 = "9306f6085165d270f7e3db02af26a400d580f5c6" +uuid = "21216c6a-2e73-6563-6e65-726566657250" +version = "1.4.3" + +[[deps.PrettyTables]] +deps = ["Crayons", "LaTeXStrings", "Markdown", "PrecompileTools", "Printf", "Reexport", "StringManipulation", "Tables"] +git-tree-sha1 = "66b20dd35966a748321d3b2537c4584cf40387c7" +uuid = "08abe8d2-0d0c-5749-adfa-8a2ac140af0d" +version = "2.3.2" + +[[deps.Printf]] +deps = ["Unicode"] +uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" + +[[deps.ProgressMeter]] +deps = ["Distributed", "Printf"] +git-tree-sha1 = "8f6bc219586aef8baf0ff9a5fe16ee9c70cb65e4" +uuid = "92933f4c-e287-5a05-a399-4b506db050ca" +version = "1.10.2" + +[[deps.PtrArrays]] +git-tree-sha1 = "f011fbb92c4d401059b2212c05c0601b70f8b759" +uuid = "43287f4e-b6f4-7ad1-bb20-aadabca52c3d" +version = "1.2.0" + +[[deps.QuadGK]] +deps = ["DataStructures", "LinearAlgebra"] +git-tree-sha1 = "e237232771fdafbae3db5c31275303e056afaa9f" +uuid = "1fd47b50-473d-5c70-9696-f719f8f3bcdc" +version = "2.10.1" + +[[deps.REPL]] +deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"] +uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" + +[[deps.Random]] +deps = ["SHA"] +uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" + +[[deps.Reexport]] +git-tree-sha1 = "45e428421666073eab6f2da5c9d310d99bb12f9b" +uuid = "189a3867-3050-52da-a836-e630ba90ab69" +version = "1.2.2" + +[[deps.Requires]] +deps = ["UUIDs"] +git-tree-sha1 = "838a3a4188e2ded87a4f9f184b4b0d78a1e91cb7" +uuid = "ae029012-a4dd-5104-9daa-d747884805df" +version = "1.3.0" + +[[deps.Rmath]] +deps = ["Random", "Rmath_jll"] +git-tree-sha1 = "f65dcb5fa46aee0cf9ed6274ccbd597adc49aa7b" +uuid = "79098fc4-a85e-5d69-aa6a-4863f24498fa" +version = "0.7.1" + +[[deps.Rmath_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "e60724fd3beea548353984dc61c943ecddb0e29a" +uuid = "f50d1b31-88e8-58de-be2c-1cc44531875f" +version = "0.4.3+0" + +[[deps.SHA]] +uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" +version = "0.7.0" + +[[deps.Scratch]] +deps = ["Dates"] +git-tree-sha1 = "3bac05bc7e74a75fd9cba4295cde4045d9fe2386" +uuid = "6c6a2e73-6563-6170-7368-637461726353" +version = "1.2.1" + +[[deps.SentinelArrays]] +deps = ["Dates", "Random"] +git-tree-sha1 = "ff11acffdb082493657550959d4feb4b6149e73a" +uuid = "91c51154-3ec4-41a3-a24f-3f23e20d615c" +version = "1.4.5" + +[[deps.Serialization]] +uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" + +[[deps.ShiftedArrays]] +git-tree-sha1 = "503688b59397b3307443af35cd953a13e8005c16" +uuid = "1277b4bf-5013-50f5-be3d-901d8477a67a" +version = "2.0.0" + +[[deps.Sockets]] +uuid = "6462fe0b-24de-5631-8697-dd941f90decc" + +[[deps.SortingAlgorithms]] +deps = ["DataStructures"] +git-tree-sha1 = "66e0a8e672a0bdfca2c3f5937efb8538b9ddc085" +uuid = "a2af1166-a08f-5f64-846c-94a0d3cef48c" +version = "1.2.1" + +[[deps.SparseArrays]] +deps = ["Libdl", "LinearAlgebra", "Random", "Serialization", "SuiteSparse_jll"] +uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" +version = "1.10.0" + +[[deps.SpecialFunctions]] +deps = ["IrrationalConstants", "LogExpFunctions", "OpenLibm_jll", "OpenSpecFun_jll"] +git-tree-sha1 = "2f5d4697f21388cbe1ff299430dd169ef97d7e14" +uuid = "276daf66-3868-5448-9aa4-cd146d93841b" +version = "2.4.0" + + [deps.SpecialFunctions.extensions] + SpecialFunctionsChainRulesCoreExt = "ChainRulesCore" + + [deps.SpecialFunctions.weakdeps] + ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" + +[[deps.SplitApplyCombine]] +deps = ["Dictionaries", "Indexing"] +git-tree-sha1 = "c06d695d51cfb2187e6848e98d6252df9101c588" +uuid = "03a91e81-4c3e-53e1-a0a4-9c0c8f19dd66" +version = "1.2.3" + +[[deps.Static]] +deps = ["CommonWorldInvalidations", "IfElse", "PrecompileTools"] +git-tree-sha1 = "87d51a3ee9a4b0d2fe054bdd3fc2436258db2603" +uuid = "aedffcd0-7271-4cad-89d0-dc628f76c6d3" +version = "1.1.1" + +[[deps.StaticArrays]] +deps = ["LinearAlgebra", "PrecompileTools", "Random", "StaticArraysCore"] +git-tree-sha1 = "eeafab08ae20c62c44c8399ccb9354a04b80db50" +uuid = "90137ffa-7385-5640-81b9-e52037218182" +version = "1.9.7" + + [deps.StaticArrays.extensions] + StaticArraysChainRulesCoreExt = "ChainRulesCore" + StaticArraysStatisticsExt = "Statistics" + + [deps.StaticArrays.weakdeps] + ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" + Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" + +[[deps.StaticArraysCore]] +git-tree-sha1 = "192954ef1208c7019899fbf8049e717f92959682" +uuid = "1e83bf80-4336-4d27-bf5d-d5a4f845583c" +version = "1.4.3" + +[[deps.Statistics]] +deps = ["LinearAlgebra", "SparseArrays"] +uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" +version = "1.10.0" + +[[deps.StatsAPI]] +deps = ["LinearAlgebra"] +git-tree-sha1 = "1ff449ad350c9c4cbc756624d6f8a8c3ef56d3ed" +uuid = "82ae8749-77ed-4fe6-ae5f-f523153014b0" +version = "1.7.0" + +[[deps.StatsBase]] +deps = ["DataAPI", "DataStructures", "LinearAlgebra", "LogExpFunctions", "Missings", "Printf", "Random", "SortingAlgorithms", "SparseArrays", "Statistics", "StatsAPI"] +git-tree-sha1 = "5cf7606d6cef84b543b483848d4ae08ad9832b21" +uuid = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91" +version = "0.34.3" + +[[deps.StatsFuns]] +deps = ["HypergeometricFunctions", "IrrationalConstants", "LogExpFunctions", "Reexport", "Rmath", "SpecialFunctions"] +git-tree-sha1 = "cef0472124fab0695b58ca35a77c6fb942fdab8a" +uuid = "4c63d2b9-4356-54db-8cca-17b64c39e42c" +version = "1.3.1" + + [deps.StatsFuns.extensions] + StatsFunsChainRulesCoreExt = "ChainRulesCore" + StatsFunsInverseFunctionsExt = "InverseFunctions" + + [deps.StatsFuns.weakdeps] + ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" + InverseFunctions = "3587e190-3f89-42d0-90ee-14403ec27112" + +[[deps.StatsModels]] +deps = ["DataAPI", "DataStructures", "LinearAlgebra", "Printf", "REPL", "ShiftedArrays", "SparseArrays", "StatsAPI", "StatsBase", "StatsFuns", "Tables"] +git-tree-sha1 = "5cf6c4583533ee38639f73b880f35fc85f2941e0" +uuid = "3eaba693-59b7-5ba5-a881-562e759f1c8d" +version = "0.7.3" + +[[deps.StringManipulation]] +deps = ["PrecompileTools"] +git-tree-sha1 = "a04cabe79c5f01f4d723cc6704070ada0b9d46d5" +uuid = "892a3eda-7b42-436c-8928-eab12a02cf0e" +version = "0.3.4" + +[[deps.StructTypes]] +deps = ["Dates", "UUIDs"] +git-tree-sha1 = "ca4bccb03acf9faaf4137a9abc1881ed1841aa70" +uuid = "856f2bd8-1eba-4b0a-8007-ebc267875bd4" +version = "1.10.0" + +[[deps.SuiteSparse]] +deps = ["Libdl", "LinearAlgebra", "Serialization", "SparseArrays"] +uuid = "4607b0f0-06f3-5cda-b6b1-a6196a1729e9" + +[[deps.SuiteSparse_jll]] +deps = ["Artifacts", "Libdl", "libblastrampoline_jll"] +uuid = "bea87d4a-7f5b-5778-9afe-8cc45184846c" +version = "7.2.1+1" + +[[deps.TOML]] +deps = ["Dates"] +uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76" +version = "1.0.3" + +[[deps.TZJData]] +deps = ["Artifacts"] +git-tree-sha1 = "1607ad46cf8d642aa779a1d45af1c8620dbf6915" +uuid = "dc5dba14-91b3-4cab-a142-028a31da12f7" +version = "1.2.0+2024a" + +[[deps.TableTraits]] +deps = ["IteratorInterfaceExtensions"] +git-tree-sha1 = "c06b2f539df1c6efa794486abfb6ed2022561a39" +uuid = "3783bdb8-4a98-5b6b-af9a-565f29a5fe9c" +version = "1.0.1" + +[[deps.Tables]] +deps = ["DataAPI", "DataValueInterfaces", "IteratorInterfaceExtensions", "OrderedCollections", "TableTraits"] +git-tree-sha1 = "598cd7c1f68d1e205689b1c2fe65a9f85846f297" +uuid = "bd369af6-aec1-5ad0-b16a-f7cc5008161c" +version = "1.12.0" + +[[deps.Tar]] +deps = ["ArgTools", "SHA"] +uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e" +version = "1.10.0" + +[[deps.Test]] +deps = ["InteractiveUtils", "Logging", "Random", "Serialization"] +uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[[deps.TimeZones]] +deps = ["Dates", "Downloads", "InlineStrings", "Mocking", "Printf", "Scratch", "TZJData", "Unicode", "p7zip_jll"] +git-tree-sha1 = "b92aebdd3555f3a7e3267cf17702033c2814ef48" +uuid = "f269a46b-ccf7-5d73-abea-4c690281aa53" +version = "1.18.0" + + [deps.TimeZones.extensions] + TimeZonesRecipesBaseExt = "RecipesBase" + + [deps.TimeZones.weakdeps] + RecipesBase = "3cdcf5f2-1ef4-517c-9805-6587b60abb01" + +[[deps.TranscodingStreams]] +git-tree-sha1 = "d73336d81cafdc277ff45558bb7eaa2b04a8e472" +uuid = "3bb67fe8-82b1-5028-8e26-92a6c54297fa" +version = "0.10.10" +weakdeps = ["Random", "Test"] + + [deps.TranscodingStreams.extensions] + TestExt = ["Test", "Random"] + +[[deps.TypedTables]] +deps = ["Adapt", "Dictionaries", "Indexing", "SplitApplyCombine", "Tables", "Unicode"] +git-tree-sha1 = "84fd7dadde577e01eb4323b7e7b9cb51c62c60d4" +uuid = "9d95f2ec-7b3d-5a63-8d20-e2491e220bb9" +version = "1.4.6" + +[[deps.UUIDs]] +deps = ["Random", "SHA"] +uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" + +[[deps.Unicode]] +uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" + +[[deps.WeakRefStrings]] +deps = ["DataAPI", "InlineStrings", "Parsers"] +git-tree-sha1 = "b1be2855ed9ed8eac54e5caff2afcdb442d52c23" +uuid = "ea10d353-3f73-51f8-a26c-33c1cb351aa5" +version = "1.4.2" + +[[deps.WorkerUtilities]] +git-tree-sha1 = "cd1659ba0d57b71a464a29e64dbc67cfe83d54e7" +uuid = "76eceee3-57b5-4d4a-8e66-0e911cebbf60" +version = "1.6.1" + +[[deps.ZipFile]] +deps = ["Libdl", "Printf", "Zlib_jll"] +git-tree-sha1 = "f492b7fe1698e623024e873244f10d89c95c340a" +uuid = "a5390f91-8eb1-5f08-bee0-b1d1ffed6cea" +version = "0.10.1" + +[[deps.Zlib_jll]] +deps = ["Libdl"] +uuid = "83775a58-1f1d-513f-b197-d71354ab007a" +version = "1.2.13+1" + +[[deps.Zstd_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "e678132f07ddb5bfa46857f0d7620fb9be675d3b" +uuid = "3161d3a3-bdf6-5164-811a-617609db77b4" +version = "1.5.6+0" + +[[deps.libblastrampoline_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "8e850b90-86db-534c-a0d3-1478176c7d93" +version = "5.8.0+1" + +[[deps.nghttp2_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d" +version = "1.52.0+1" + +[[deps.p7zip_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0" +version = "17.4.0+2" diff --git a/issues/780/Project.toml b/issues/780/Project.toml new file mode 100644 index 000000000..72052ff9f --- /dev/null +++ b/issues/780/Project.toml @@ -0,0 +1,10 @@ +[deps] +Arrow = "69666777-d1a9-59fb-9406-91d4454c9d45" +CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" +DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" +Downloads = "f43a241f-c20a-4ad4-852c-f6b1247861c6" +LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" +MixedModels = "ff71e718-51f3-5ec2-a782-8ffcbfa3c316" +Scratch = "6c6a2e73-6563-6170-7368-637461726353" +Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" +ZipFile = "a5390f91-8eb1-5f08-bee0-b1d1ffed6cea" diff --git a/issues/780/issue.jl b/issues/780/issue.jl new file mode 100644 index 000000000..df70d8d4f --- /dev/null +++ b/issues/780/issue.jl @@ -0,0 +1,120 @@ +module IssueData + using Arrow + using CSV + using DataFrames + using Downloads + using Scratch + using ZipFile + + export get_data + + const CACHE = Ref("") + const URL = "https://github.com/user-attachments/files/16604579/testdataforjulia_bothcase.zip" + + function extract_csv(zipfile, fname; delim=',', header=1, kwargs...) + file = only(filter(f -> endswith(f.name, fname), zipfile.files)) + return CSV.read(file, DataFrame; delim, header, kwargs...) + end + + function get_data() + path = joinpath(CACHE[], "780.arrow") + + isfile(path) && return DataFrame(Arrow.Table(path); copycols=true) + + @info "downloading..." + data = open(Downloads.download(URL), "r") do io + zipfile = ZipFile.Reader(io) + @info "extracting..." + return extract_csv(zipfile, "testdataforjulia_bothcase.csv") + end + + transform!(data, :individual_local_identifier => ByRow(string); renamecols=false), + Arrow.write(path, data) + return data + end + + clear_scratchspaces!() = rm.(readdir(CACHE[])) + + function __init__() + CACHE[] = get_scratch!(Main, "780") + return nothing + end +end + +using DataFrames +using .IssueData +using LinearAlgebra +using MixedModels +using Statistics + +data = get_data() +m0form = @formula(case ~ 0 + Analysisclass + (1|cropyear/individual_local_identifier)) + +# fails +model = fit(MixedModel, m0form, data, Bernoulli(); + wts=float.(data.weights), + contrasts= Dict(:Analysisclass => DummyCoding(; base="aRice_Wet_day")), + fast=false, + progress=true, + verbose=false) + +# works on amd64, non singular, FE look okay +model = fit(MixedModel, m0form, data, Bernoulli(); + wts=float.(data.weights), + contrasts= Dict(:Analysisclass => DummyCoding(; base="aRice_Wet_day")), + init_from_lmm=[:θ], + fast=false, + progress=true, + verbose=false) + +# works on m1, singular and has questionable FE +m0fast = fit(MixedModel, m0form, data, Bernoulli(); + wts=float.(data.weights), + contrasts= Dict(:Analysisclass => DummyCoding(; base="aRice_Wet_day")), + fast=true, + progress=true, + verbose=false) + +# this model is singular in cropyear, but it looks like there is proper nesting: +groups = select(data, :cropyear, :individual_local_identifier) +unique(groups) +unique(groups, :cropyear) +unique(groups, :individual_local_identifier) + +# the estimates for `Nonhabitat_Wet_day` and `Nonhabitat_Wet_night` are identical, +# which seems suspicious, and they have very large standard errors. I think +# this hints at undetected collinearity. +X = modelmatrix(m0fast) +rank(X) # =12 +idx = findall(coefnames(m0fast)) do x + return x in ("Analysisclass: Nonhabitat_Wet_day", "Analysisclass: Nonhabitat_Wet_night") +end + +cols = X[:, idx] +# AHA 98% of values are identical because these measurements are very sparse +mean(cols[:, 1] .== cols[:, 2]) +mean(cols[:, 1]) +mean(cols[:, 2]) + +counts = sort!(combine(groupby(data, :Analysisclass), nrow => :n), :n) +transform!(counts, :n => ByRow(x -> round(100x / sum(counts.n); digits=1)) => "%") + +# let's try reparameterizing + +transform!(data, :Analysisclass => ByRow(ac -> NamedTuple{(:habitat, :wet, :time)}(split(ac, "_"))) => AsTable) + +m1form = @formula(case ~ 0 + habitat * wet * time + (1|cropyear & individual_local_identifier)) + +# fails really fast with a PosDefException +m1fast = fit(MixedModel, m1form, data, Bernoulli(); + wts=float.(data.weights), + fast=true, + progress=true, + verbose=false) + +# still fails +m1 = fit(MixedModel, m1form, data, Bernoulli(); + wts=float.(data.weights), + fast=false, + progress=true, + verbose=false) From 0ad05945c060bc95f401664bd2f6971772fdc317 Mon Sep 17 00:00:00 2001 From: Douglas Bates Date: Fri, 16 Aug 2024 10:32:03 -0500 Subject: [PATCH 13/13] Add checks on complete separation --- issues/780/issue.jl | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/issues/780/issue.jl b/issues/780/issue.jl index df70d8d4f..2603b111b 100644 --- a/issues/780/issue.jl +++ b/issues/780/issue.jl @@ -25,10 +25,18 @@ module IssueData data = open(Downloads.download(URL), "r") do io zipfile = ZipFile.Reader(io) @info "extracting..." - return extract_csv(zipfile, "testdataforjulia_bothcase.csv") + return extract_csv( + zipfile, + "testdataforjulia_bothcase.csv"; + missingstring=["NA"], + downcast=true, + types=Dict( + :case => Bool, + :individual_local_identifier => String15, + ) + ) end - transform!(data, :individual_local_identifier => ByRow(string); renamecols=false), Arrow.write(path, data) return data end @@ -48,6 +56,33 @@ using MixedModels using Statistics data = get_data() + +# check for complete separation of response within levels of columns used as predictors + +println( + unstack( + combine(groupby(data, [:Analysisclass, :case]), nrow => :n), + :case, + :n + ), +) + +println( + unstack( + combine(groupby(data, [:individual_local_identifier, :case]), nrow => :n), + :case, + :n, + ), +) + +println( + unstack( + combine(groupby(data, [:cropyear, :case]), nrow => :n), + :case, + :n, + ), +) + m0form = @formula(case ~ 0 + Analysisclass + (1|cropyear/individual_local_identifier)) # fails