Skip to content

Commit 312b897

Browse files
dmbatespalday
andauthored
Nicer describeblocks output (#299)
* Nicer describeblocks output * Replace describeblocks by BlockDescription Co-authored-by: Phillip Alday <[email protected]>
1 parent 7c9a281 commit 312b897

File tree

5 files changed

+102
-27
lines changed

5 files changed

+102
-27
lines changed

src/MixedModels.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export @formula,
3535
Bernoulli,
3636
Binomial,
3737
Block,
38+
BlockDescription,
3839
BlockedSparse,
3940
DummyCoding,
4041
EffectsCoding,
@@ -150,5 +151,6 @@ include("linalg/logdet.jl")
150151
include("linalg.jl")
151152
include("simulate.jl")
152153
include("bootstrap.jl")
154+
include("blockdescription.jl")
153155

154156
end # module

src/blockdescription.jl

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
"""
2+
BlockDescription
3+
4+
Description of blocks of `A` and `L` in a [`LinearMixedModel`](@ref)
5+
6+
## Fields
7+
* `blknms`: Vector{String} of block names
8+
* `blkrows`: Vector{Int} of the number of rows in each block
9+
* `ALtypes`: Matrix{String} of datatypes for blocks in `A` and `L`.
10+
11+
When a block in `L` is the same type as the corresponding block in `A`, it is
12+
described with a single name, such as `Dense`. When the types differ the entry
13+
in `ALtypes` is of the form `Diag/Dense`, as determined by a `shorttype` method.
14+
"""
15+
struct BlockDescription
16+
blknms::Vector{String}
17+
blkrows::Vector{Int}
18+
ALtypes::Matrix{String}
19+
end
20+
function BlockDescription(m::LinearMixedModel)
21+
A = m.A
22+
L = m.L
23+
blknms = push!(string.([fnames(m)...]), "fixed")
24+
k = length(blknms)
25+
ALtypes = fill("", k, k)
26+
Ltypes = fill(Nothing, k, k)
27+
for i in 1:k, j in 1:i
28+
ALtypes[i, j] = shorttype(A[Block(i,j)], L[Block(i,j)])
29+
end
30+
BlockDescription(
31+
blknms,
32+
[size(A[Block(i, 1)], 1) for i in 1:k],
33+
ALtypes,
34+
)
35+
end
36+
37+
BlockDescription(m::GeneralizedLinearMixedModel) = BlockDescription(m.LMM)
38+
39+
shorttype(::UniformBlockDiagonal,::UniformBlockDiagonal) = "BlkDiag"
40+
shorttype(::UniformBlockDiagonal,::Matrix) = "BlkDiag/Dense"
41+
shorttype(::SparseMatrixCSC,::BlockedSparse) = "Sparse"
42+
shorttype(::Diagonal,::Diagonal) = "Diagonal"
43+
shorttype(::Diagonal,::Matrix) = "Diag/Dense"
44+
shorttype(::Matrix,::Matrix) = "Dense"
45+
shorttype(::SparseMatrixCSC,::SparseMatrixCSC) = "Sparse"
46+
47+
function Base.show(io::IO, ::MIME"text/plain", b::BlockDescription)
48+
rowwidth = max(maximum(ndigits, b.blkrows) + 1, 5)
49+
colwidth = max(maximum(textwidth, b.blknms) + 1, 14)
50+
print(io, rpad("rows:", rowwidth))
51+
println(io, cpad.(b.blknms, colwidth)...)
52+
for (i, r) in enumerate(b.blkrows)
53+
print(io, lpad(string(r, ':'), rowwidth))
54+
for j in 1:i
55+
print(io, cpad(b.ALtypes[i, j], colwidth))
56+
end
57+
println(io)
58+
end
59+
end
60+
Base.show(io::IO, b::BlockDescription) = show(io, MIME"text/plain"(), b)
61+
62+
@deprecate describeblocks(io, m) show(io, BlockDescription(m))
63+
@deprecate describeblocks(m) show(stdout, BlockDescription(m))

src/linearmixedmodel.jl

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -251,32 +251,6 @@ function createAL(allterms::Vector{Union{ReMat{T},FeMat{T}}}) where {T}
251251
A, L
252252
end
253253

254-
"""
255-
describeblocks(io::IO, m::MixedModel)
256-
describeblocks(m::MixedModel)
257-
258-
Describe the types and sizes of the blocks in the lower triangle of `m.A` and `m.L`.
259-
"""
260-
function describeblocks(io::IO, m::LinearMixedModel)
261-
A = m.A
262-
L = m.L
263-
for i = 1:length(m.allterms), j = 1:i
264-
Aij = A[Block(i,j)]
265-
println(
266-
io,
267-
i,
268-
",",
269-
j,
270-
": ",
271-
typeof(Aij),
272-
" ",
273-
size(Aij),
274-
" ",
275-
typeof(L[Block(i, j)]),
276-
)
277-
end
278-
end
279-
describeblocks(m::MixedModel) = describeblocks(stdout, m)
280254

281255
StatsBase.deviance(m::MixedModel) = objective(m)
282256

test/pirls.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ using Test
3737
#@test isapprox(sum(abs2, gm1.u[1]), 48.4747, atol=0.1)
3838
#@test isapprox(sum(gm1.resp.devresid), 2237.349, atol=0.1)
3939
show(IOBuffer(), gm1)
40+
show(IOBuffer(), BlockDescription(gm0))
4041
end
4142

4243
@testset "cbpp" begin

test/pls.jl

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,35 @@ using Tables
1010
using Test
1111

1212
const LMM = LinearMixedModel
13+
const forms = Dict(
14+
:dyestuff => [@formula(yield ~ 1 + (1|batch))],
15+
:dyestuff2 => [@formula(yield ~ 1 + (1|batch))],
16+
:d3 => [@formula(y ~ 1 + u + (1+u|g) + (1+u|h) + (1+u|i))],
17+
:insteval => [
18+
@formula(y ~ 1 + service + (1|s) + (1|d) + (1|dept)),
19+
@formula(y ~ 1 + service*dept + (1|s) + (1|d)),
20+
],
21+
:kb07 => [
22+
@formula(rt_trunc ~ 1+spkr+prec+load+(1|subj)+(1|item)),
23+
@formula(rt_trunc ~ 1+spkr*prec*load+(1|subj)+(1+prec|item)),
24+
@formula(rt_trunc ~ 1+spkr*prec*load+(1+spkr+prec+load|subj)+(1+spkr+prec+load|item)),
25+
],
26+
:ml1m => [@formula(Y ~ 1 + (1|G) + (1|H))],
27+
:pastes => [
28+
@formula(strength ~ 1 + (1|sample)),
29+
@formula(strength ~ 1 + (1|sample) + (1|batch)),
30+
],
31+
:penicillin => [@formula(diameter ~ 1 + (1|plate) + (1|sample))],
32+
:sleepstudy => [
33+
@formula(reaction ~ 1 + days + (1|subj)),
34+
@formula(reaction ~ 1 + days + zerocorr(1+days|subj)),
35+
@formula(reaction ~ 1 + days + (1+days|subj)),
36+
],
37+
)
38+
39+
#= # replace all the model fits by
40+
fits = Dict(k => fit.(MixedModel, forms[k], Ref(MixedModels.dataset[k])) for k in keys(forms))
41+
=#
1342

1443
@testset "Dyestuff" begin
1544
ds = MixedModels.dataset(:dyestuff)
@@ -25,7 +54,13 @@ const LMM = LinearMixedModel
2554
@test_logs (:warn, "Model has not been fit") show(fm1)
2655

2756
@test objective(updateL!(setθ!(fm1, [0.713]))) 327.34216280955366
28-
MixedModels.describeblocks(IOBuffer(), fm1)
57+
@test_deprecated MixedModels.describeblocks(IOBuffer(), fm1)
58+
59+
io = IOBuffer()
60+
show(io, BlockDescription(fm1))
61+
@test countlines(seekstart(io)) == 3
62+
output = String(take!(io))
63+
@test startswith(output, "rows:")
2964

3065
fit!(fm1);
3166
@test in propertynames(fm1)

0 commit comments

Comments
 (0)