Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Dev #51

Merged
merged 5 commits into from
Dec 18, 2024
Merged

Dev #51

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ uuid = "a1dec852-9fe5-11e9-361f-8d9fde67cfa2"
keywords = ["lenearmodel", "mixedmodel"]
desc = "Mixed-effects models with flexible covariance structure."
authors = ["Vladimir Arnautov <[email protected]>"]
version = "0.16.2"
version = "0.16.3"

[deps]
DiffResults = "163ba53b-c6d8-5494-b064-1a9d43ac40c5"
Expand Down
7 changes: 7 additions & 0 deletions docs/src/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,13 @@ Metida.SpatialPowerD
Metida.ScaledWeightedCov
```

### Metida.ACOV

```@docs
Metida.ACOV
```


### Metida.dof_contain

```@docs
Expand Down
90 changes: 82 additions & 8 deletions docs/src/examples.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
### Example 1 - Continuous and categorical predictors
## Example 1 - Continuous and categorical predictors

```@example lmmexample
using Metida, CSV, DataFrames, CategoricalArrays, MixedModels;

rds = CSV.File(joinpath(dirname(pathof(Metida)), "..", "test", "csv", "1fptime.csv"); types = [String, String, Float64, Float64]) |> DataFrame

rds2 = CSV.File(joinpath(dirname(pathof(Metida)), "..", "test", "csv", "ftdf3.csv"); types = [String, Float64, Float64, String, String, String, String, String, Float64]) |> DataFrame


devday = CSV.File(joinpath(dirname(pathof(Metida)), "..", "test", "csv", "devday.csv"); types = [Float64, String, String, String ]) |> DataFrame

nothing; # hide
```

Expand All @@ -27,7 +32,7 @@ mm = fit(MixedModel, fm, rds, REML=true)
println(mm) #hide
```

### Example 2 - Two random factors (Penicillin data)
## Example 2 - Two random factors (Penicillin data)

Metida:

Expand All @@ -51,7 +56,7 @@ mm = fit(MixedModel, fm2, df, REML=true)
println(mm) #hide
```

### Example 3 - Repeated ARMA/AR/ARH
## Example 3 - Repeated ARMA/AR/ARH

```@example lmmexample
rds = CSV.File(joinpath(dirname(pathof(Metida)), "..", "test", "csv", "1freparma.csv"); types = [String, String, Float64, Float64]) |> DataFrame
Expand Down Expand Up @@ -91,9 +96,9 @@ repeated = VarEffect(@covstr(1|subject&factor), ARH),
fit!(lmm)
```

### Example 4 - SAS relation
## Example 4 - SAS relation

#### Model 1
### Model 1

```
df0 = CSV.File(joinpath(dirname(pathof(Metida)), "..", "test", "csv", "df0.csv")) |> DataFrame
Expand All @@ -116,7 +121,7 @@ REPEATED/GRP=formulation SUB=subject R;
RUN;
```

#### Model 2
### Model 2

```
lmm = LMM(
Expand All @@ -138,7 +143,7 @@ REPEATED/GRP=formulation SUB=subject R;
RUN;
```

#### Model 3
### Model 3

```
lmm = LMM(@formula(var ~ sequence + period + formulation), df0;
Expand All @@ -157,7 +162,7 @@ RANDOM subject/TYPE=VC G V;
RUN;
```

### Example 5 - Working with Effects.jl
## Example 5 - Working with Effects.jl

```
using Effects, StatsModels
Expand All @@ -172,4 +177,73 @@ table_model = StatsModels.TableRegressionModel(lmm, lmm.mf, lmm.mm)
emmeans(tm)

effects(Dict(:period => ["1", "2", "3", "4"]), tm)
```


## Unstructured covariance

Unstructured covariance example.


Metida result:

```@example lmmexample
lmm = Metida.LMM(@formula(response~factor), rds2;
random = Metida.VarEffect(Metida.@covstr(r1|subject), UN),
)
Metida.fit!(lmm)
```

MixedModels result:

```@example lmmexample
mm = fit(MixedModel, @formula(response ~ factor+ (0+r1|subject)), rds2, REML = true)
println(mm) #hide
```

## Aumented covariance (Experimental)

Covariance modificator `ACOV()` can be used as second repeated effect. In this case covariance calculated with existed matrix,
that was build at previous step. For example addition `ACOV(AR)` to `DIAG` structure is the same as `ARH` if same blocking factor used.

```@example lmmexample
lmm1 = Metida.LMM(@formula(response ~ 1), rds2;
repeated = [Metida.VarEffect(Metida.@covstr(r1|subject), Metida.DIAG), Metida.VarEffect(Metida.@covstr(1|subject), Metida.ACOV(Metida.AR))]
)
Metida.fit!(lmm1)
```

```@example lmmexample
lmm2 = Metida.LMM(@formula(response ~ 1), rds2;
repeated = [Metida.VarEffect(Metida.@covstr(r1|subject), Metida.ARH)]
)
Metida.fit!(lmm2)
```

R-part of variance-covariance matrix:

```@example lmmexample
Metida.rmatrix(lmm1, 1)
```

If nested blocking factor used - covariance modification applyed only within that blocks:

```@example lmmexample
lmm = Metida.LMM(@formula(response ~ 1), rds2;
repeated = [Metida.VarEffect(Metida.@covstr(r1|subject), Metida.DIAG), Metida.VarEffect(Metida.@covstr(1|subject), Metida.ACOV(Metida.AR))]
)
Metida.fit!(lmm)
Metida.rmatrix(lmm, 1)
```

For nested models covariance structure can be expanded as follows:
* the first layer describes unstructured the device-device covariance;
* the second layer adds the time covariance for each device

```@example lmmexample
lmm = Metida.LMM(@formula(resp ~ 0 + device), devday;
repeated = [Metida.VarEffect(Metida.@covstr(device|subj&day), Metida.UN),
Metida.VarEffect(Metida.@covstr(1|subj&device), Metida.ACOV(Metida.AR))]
)
Metida.fit!(lmm)
```
1 change: 1 addition & 0 deletions src/Metida.jl
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ SPPOW, SpatialPower,
SPGAU, SpatialGaussian, RawCoding,
UN, Unstructured,
CovarianceType,
ACOV,
fit, fit!, LMM, VarEffect, theta, logreml, m2logreml, m2logml, logml, thetalength, dof_satter, dof_contain, rankx, caic, lcontrast, typeiii, estimate, contrast,
gmatrix, rmatrix, vmatrix!, responsename, nblocks, raneff,
AbstractCovarianceType, AbstractCovmatMethod, MetidaModel,
Expand Down
70 changes: 70 additions & 0 deletions src/rmat.jl
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,76 @@
mulαβαtinc!(mx, rz, rcov)
return mx
end

# ACOV (AR)
function rmat!(mx::AbstractMatrix{T}, θ, ::AbstractMatrix, ct::ACOV_{AR_}, ::Int) where T
s = size(mx, 1)
ρ = θ[1]
if s > 1
for n = 2:s
mxnn = mx[n, n]
@inbounds @simd for m = 1:n-1
mxmm = mx[m, m]
mxmn = mx[m, n]
cov = sqrt(mxnn * mxmm) * ρ ^ (n - m)
if ct.a != 0
if ct.a == 1
mxmn = zero(T)
elseif ct.a == 2
cov = zero(T)
elseif ct.a == 3
@warn "covariance have existed value!"
elseif ct.a == 4
@warn "covariance have existed value! replaced..."
mxmn = zero(T)
elseif ct.a == 5
@warn "covariance have existed value! Save existed..."
cov = zero(T)

Check warning on line 369 in src/rmat.jl

View check run for this annotation

Codecov / codecov/patch

src/rmat.jl#L358-L369

Added lines #L358 - L369 were not covered by tests
else
error("covariance have existed value!")

Check warning on line 371 in src/rmat.jl

View check run for this annotation

Codecov / codecov/patch

src/rmat.jl#L371

Added line #L371 was not covered by tests
end
end
mx[m, n] = mxmn + cov
end

Check warning on line 375 in src/rmat.jl

View check run for this annotation

Codecov / codecov/patch

src/rmat.jl#L375

Added line #L375 was not covered by tests
end
end
return mx
end

# ACOV (CS)
function rmat!(mx::AbstractMatrix{T}, θ, ::AbstractMatrix, ct::ACOV_{CS_}, ::Int) where T
s = size(mx, 1)
ρ = θ[1]
if s > 1
for n = 2:s
mxnn = mx[n, n]
@inbounds @simd for m = 1:n-1
mxmm = mx[m, m]
mxmn = mx[m, n]
cov = sqrt(mxnn * mxmm) * ρ
if ct.a != 0
if ct.a == 1
mxmn = zero(T)
elseif ct.a == 2
cov = zero(T)
elseif ct.a == 3
@warn "covariance have existed value!"
elseif ct.a == 4
@warn "covariance have existed value! replaced..."
mxmn = zero(T)
elseif ct.a == 5
@warn "covariance have existed value! Save existed..."
cov = zero(T)

Check warning on line 404 in src/rmat.jl

View check run for this annotation

Codecov / codecov/patch

src/rmat.jl#L393-L404

Added lines #L393 - L404 were not covered by tests
else
error("covariance have existed value!")

Check warning on line 406 in src/rmat.jl

View check run for this annotation

Codecov / codecov/patch

src/rmat.jl#L406

Added line #L406 was not covered by tests
end
end
mx[m, n] = mxmn + cov
end

Check warning on line 410 in src/rmat.jl

View check run for this annotation

Codecov / codecov/patch

src/rmat.jl#L410

Added line #L410 was not covered by tests
end
end
return mx
end
###############################################################################
###############################################################################
###############################################################################
Expand Down
17 changes: 14 additions & 3 deletions src/varstruct.jl
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
# Example

```julia
@covstr(factor|subject)
@covstr(model|subject)
```
"""
macro covstr(ex)
Expand Down Expand Up @@ -64,7 +64,7 @@

!!! note

Categorical factors are coded with `FullDummyCoding()` by default, use `coding` for other contrast codeing.
Categorical factors are coded with `FullDummyCoding()` by default, use `coding` for other contrast coding.

# Example

Expand Down Expand Up @@ -352,6 +352,9 @@
subjblockdict = sabjcrossdicts(subjblockdict, dicts[i])
end
end
if isa(repeated[1].covtype.s, ACOV_)
@warn "Using ACOV covariance additional effect at first position is meaningless."

Check warning on line 356 in src/varstruct.jl

View check run for this annotation

Codecov / codecov/patch

src/varstruct.jl#L356

Added line #L356 was not covered by tests
end
else
subjblockdict = nothing
end
Expand Down Expand Up @@ -432,7 +435,15 @@
# CONTRAST CODING
################################################################################

function fill_coding_dict!(t::T, d::Dict, data) where T <: Union{ConstantTerm, InterceptTerm, FunctionTerm}
function fill_coding_dict!(t::T, d::Dict, data) where T <: Union{ConstantTerm, InterceptTerm}
return d
end
function fill_coding_dict!(t::T, d::Dict, data) where T <: FunctionTerm
if t.f === +
for i in t.args
fill_coding_dict!(i, d, data)
end
end
return d
end
function fill_coding_dict!(t::T, d::Dict, data) where T <: Term
Expand Down
43 changes: 43 additions & 0 deletions src/vartypes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ struct SPGAUD_ <: AbstractCovarianceType end
struct UN_ <: AbstractCovarianceType end
struct ZERO <: AbstractCovarianceType end

struct ACOV_{C <: AbstractCovarianceType} <: AbstractCovarianceType
c::C
a::Int
end

################################################################################
# COVARIANCE TYPE
################################################################################
Expand Down Expand Up @@ -399,10 +404,37 @@ function Unstructured()
end
const UN = Unstructured()


"""
ACOV(c, action = 0)

!!! warning
Experimental

Augmented (adjusted) covariance. Add additional correlations to existed R-part of variance covariance matrix.
Can be used with `AR` or `CS` types.

`action` if existed covariance not equal sero:

* 0 - add
* 1 - replace
* 2 - do nothing (use existed value)
* 3 - warning and add
* 4 - warning and replace
* 5 - warning and use existed value
* other - error

"""
function ACOV(c; action = 0)
CovarianceType(ACOV_(c.s, action))
end

function RZero()
CovarianceType(ZERO(), false)
end

#######################################################################################

function covstrparam(ct::SI_, ::Int)::Tuple{Int, Int}
return (1, 0)
end
Expand Down Expand Up @@ -446,6 +478,10 @@ function covstrparam(ct::SPPOWD_, ::Int)::Tuple{Int, Int}
return (2, 1)
end

function covstrparam(ct::ACOV_{<:Union{CS_, AR_, SPPOW_}}, ::Int)::Tuple{Int, Int}
return (0, 1)
end

function covstrparam(ct::ZERO, ::Int)::Tuple{Int, Int}
return (0, 0)
end
Expand Down Expand Up @@ -555,6 +591,10 @@ function rcoefnames(s, t, ct::UN_)
return v
end

function rcoefnames(s, t, ct::ACOV_{<: Union{CS_, AR_}})
return ["ρ "]
end

function rcoefnames(s, t, ct::AbstractCovarianceType)
v = Vector{String}(undef, t)
v .= "Val "
Expand Down Expand Up @@ -643,6 +683,9 @@ end
function Base.show(io::IO, ct::UN_)
print(io, "UN")
end
function Base.show(io::IO, ct::ACOV_)
print(io, "ACOV(", ct.c, ")")
end
function Base.show(io::IO, ct::ZERO)
print(io, "No effect")
end
Loading
Loading