Skip to content

Commit

Permalink
shortestcovint for MixedModelBootstrap objects (#484)
Browse files Browse the repository at this point in the history
* shortestcovint for MixedModelBootstrap objects

* news update

* minor version bump

* release notes text update

* showcase new method in docs
  • Loading branch information
palday committed Mar 8, 2021
1 parent 5cd943d commit 4218789
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 14 deletions.
17 changes: 11 additions & 6 deletions .github/workflows/TagBot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,31 @@ jobs:
ssh: ${{ secrets.DOCUMENTER_KEY }} # see https://juliadocs.github.io/Documenter.jl/stable/man/hosting/#GitHub-Actions
changelog: |
## {{ package }} {{ version }}
{% if previous_release %}
[NEWS file](https://github.com/JuliaStats/MixedModels.jl/blob/{{ version }}/NEWS.md).
[NEWS file](https://github.com/JuliaStats/MixedModels.jl/blob/{{ version }}/NEWS.md).
[Diff since {{ previous_release }}]({{ compare_url }})
{% endif %}
{% if custom %}
{{ custom }}
{% endif %}
*NB: Closed issues and pull requests are sorted temporally and so may
include backports to other versions or work in the development branch for
an upcoming breaking release. Please see the [NEWS file](https://github.com/JuliaStats/MixedModels.jl/blob/{{ version }}/NEWS.md)
for changes sorted by release.*
{% if issues %}
**Closed issues:**
{% for issue in issues %}
- {{ issue.title }} (#{{ issue.number }})
{% endfor %}
{% endif %}
{% if pulls %}
**Merged pull requests:**
{% for pull in pulls %}
- {{ pull.title }} (#{{ pull.number }}) (@{{ pull.author.username }})
{% endfor %}
{% endif %}
{% endif %}
5 changes: 5 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
MixedModels v3.4.0 Release Notes
========================
* `shortestcovint` method for `MixedModelsBootstrap` [#484]

MixedModels v3.3.0 Release Notes
========================
* HTML and LaTeX `show` methods for `MixedModel`, `BlockDescription`,
Expand Down Expand Up @@ -145,3 +149,4 @@ Package dependencies
[#449]: https://github.com/JuliaStats/MixedModels.jl/issues/449
[#474]: https://github.com/JuliaStats/MixedModels.jl/issues/474
[#480]: https://github.com/JuliaStats/MixedModels.jl/issues/480
[#484]: https://github.com/JuliaStats/MixedModels.jl/issues/484
2 changes: 1 addition & 1 deletion 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 <me@phillipalday.com>", "Douglas Bates <dmbates@gmail.com>", "Jose Bayoan Santiago Calderon <jbs3hp@virginia.edu>"]
version = "3.3.0"
version = "3.4.0"

[deps]
Arrow = "69666777-d1a9-59fb-9406-91d4454c9d45"
Expand Down
7 changes: 6 additions & 1 deletion docs/src/bootstrap.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,11 @@ We generate these for all random and fixed effects:
combine(groupby(df, [:type, :group, :names]), :value => shortestcovint => :interval)
```

We can also generate this directly from the original bootstrap object:
```@example Main
DataFrame(shortestcovint(samp))
```

A value of zero for the standard deviation of the random effects is an example of a *singular* covariance.
It is easy to detect the singularity in the case of a scalar random-effects term.
However, it is not as straightforward to detect singularity in vector-valued random-effects terms.
Expand All @@ -116,7 +121,7 @@ first(df2, 10)
the singularity can be exhibited as a standard deviation of zero or as a correlation of $\pm1$.

```@example Main
combine(groupby(df2, [:type, :group, :names]), :value => shortestcovint => :interval)
DataFrame(shortestcovint(samp2))
```

A histogram of the estimated correlations from the bootstrap sample has a spike at `+1`.
Expand Down
44 changes: 43 additions & 1 deletion src/bootstrap.jl
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ end
"""
allpars(bsamp::MixedModelBootstrap)
Return a tidy (row)table with the parameter estimates spread into columns
Return a tidy (column)table with the parameter estimates spread into columns
of `iter`, `type`, `group`, `name` and `value`.
"""
function allpars(bsamp::MixedModelBootstrap{T}) where {T}
Expand Down Expand Up @@ -245,6 +245,48 @@ function shortestcovint(v, level = 0.95)
(vv[i], vv[i + ilen - 1])
end

"""
shortestcovint(bsamp::MixedModelBootstrap, level = 0.95)
Return the shortest interval containing `level` proportion for each parameter from [`bsamp.allpars`](@ref)
"""
function shortestcovint(bsamp::MixedModelBootstrap{T}, level = 0.95) where {T}
allpars = bsamp.allpars
pars = unique(zip(allpars.type, allpars.group, allpars.names))

colnms = (:type, :group, :names, :lower, :upper)
coltypes = Tuple{String, Union{Missing,String}, Union{Missing,String}, T, T}
# not specifying the full eltype (NamedTuple{colnms,coltypes}) leads to prettier printing
result = NamedTuple{colnms}[]
sizehint!(result, length(pars))


for (t, g, n) in pars
gidx = if ismissing(g)
ismissing.(allpars.group)
else
.!ismissing.(allpars.group) .& (allpars.group .== g)
end

nidx = if ismissing(n)
ismissing.(allpars.names)
else
.!ismissing.(allpars.names) .& (allpars.names .== n)
end

tidx = allpars.type .== t # no missings allowed here

idx = tidx .& gidx .& nidx

vv = view(allpars.value, idx)

lower, upper = shortestcovint(vv, level)
push!(result, (; type=t, group=g, names=n, lower=lower, upper=upper))
end

return result
end

"""
tidyβ(bsamp::MixedModelBootstrap)
Return a tidy (row)table with the parameter estimates spread into columns
Expand Down
6 changes: 1 addition & 5 deletions test/bootstrap.jl
Original file line number Diff line number Diff line change
Expand Up @@ -104,11 +104,7 @@ end
contra = dataset(:contra)
gm0 = fit(MixedModel, only(gfms[:contra]), contra, Bernoulli(), fast=true)
bs = parametricbootstrap(StableRNG(42), 100, gm0)
bsci = combine(groupby(DataFrame(bs.β), :coefname),
=> shortestcovint => :ci)
bsci.lower = first.(bsci.ci)
bsci.upper = last.(bsci.ci)
select!(bsci, Not(:ci))
bsci = filter!(:type => ==("β"), DataFrame(shortestcovint(bs)))
ciwidth = 2 .* stderror(gm0)
waldci = DataFrame(coef=fixefnames(gm0),
lower=fixef(gm0) .- ciwidth,
Expand Down

2 comments on commit 4218789

@palday
Copy link
Member Author

@palday palday commented on 4218789 Mar 8, 2021

Choose a reason for hiding this comment

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

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

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

Registration pull request created: JuliaRegistries/General/31500

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

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

git tag -a v3.4.0 -m "<description of version>" 4218789b9020540c48afc2bcf4104676d66bf4a3
git push origin v3.4.0

Please sign in to comment.