Refactor Sem multi-group support#317
Open
alyst wants to merge 18 commits intoStructuralEquationModels:develfrom
Open
Refactor Sem multi-group support#317alyst wants to merge 18 commits intoStructuralEquationModels:develfrom
alyst wants to merge 18 commits intoStructuralEquationModels:develfrom
Conversation
3c39941 to
32cea82
Compare
- for SemImplied require spec::SemSpec as positional - for SemLossFunction require implied argument
32cea82 to
eb039a2
Compare
deduplicate the correction scale methods and move to Sem.jl
remove update_observed!()
to suppress info about inv(obs_cov)
eb039a2 to
88a1ff0
Compare
88a1ff0 to
0406f29
Compare
Comment on lines
+6
to
+7
| In this case, [`FiniteDiffWrapper`](@ref) method to generate a wrapper around the specific `SemLoss` term that only uses its objective | ||
| to calculate the gradient using the finite difference approximation. |
Collaborator
There was a problem hiding this comment.
Suggested change
| In this case, [`FiniteDiffWrapper`](@ref) method to generate a wrapper around the specific `SemLoss` term that only uses its objective | |
| to calculate the gradient using the finite difference approximation. | |
| In this case, [`FiniteDiffWrapper`](@ref) can be used to generate a wrapper around the specific `SemLoss` term. This wrapper only uses the `LossTerm`s objective, and calculates the gradient using finite difference approximation. |
Contributor
Author
|
@Maximilian-Stefan-Ernst It might be a nice idea to use copilot for catching typos, incorrect sentences, but also potential bugs. |
| function χ²(fit::SemFit, model::AbstractSemSingle) | ||
| check_single_lossfun(model; throw_error = true) | ||
| return χ²(model.loss.functions[1], fit::SemFit, model::AbstractSemSingle) | ||
| return χ²(typeof(term1), fit, model) |
Collaborator
There was a problem hiding this comment.
Is there a reason to pass typeof(term1) instead of term1? I personally find the syntax a bit cleaner without the extra typeof call.
| ############################################################################################ | ||
| function χ²(fit::SemFit, model::AbstractSem) | ||
| terms = sem_terms(model) | ||
| isempty(terms) && return 0.0 |
Collaborator
There was a problem hiding this comment.
Maybe we should throw an error for a Sem with no terms?
Comment on lines
+20
to
+30
| term1 = _unwrap(loss(terms[1])) | ||
| L = typeof(term1).name | ||
|
|
||
| # check that all SemLoss terms are of the same class (ML, FIML, WLS etc), ignore typeparams | ||
| for (i, term) in enumerate(terms) | ||
| lossterm = _unwrap(loss(term)) | ||
| @assert lossterm isa SemLoss | ||
| if typeof(_unwrap(lossterm)).name != L | ||
| @error "SemLoss term #$i is $(typeof(_unwrap(lossterm)).name), expected $L. Heterogeneous loss functions are not supported" | ||
| end | ||
| end |
Collaborator
There was a problem hiding this comment.
I thought this is done in check_semterm_type?
Suggested change
| term1 = _unwrap(loss(terms[1])) | |
| L = typeof(term1).name | |
| # check that all SemLoss terms are of the same class (ML, FIML, WLS etc), ignore typeparams | |
| for (i, term) in enumerate(terms) | |
| lossterm = _unwrap(loss(term)) | |
| @assert lossterm isa SemLoss | |
| if typeof(_unwrap(lossterm)).name != L | |
| @error "SemLoss term #$i is $(typeof(_unwrap(lossterm)).name), expected $L. Heterogeneous loss functions are not supported" | |
| end | |
| end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This is a largest remaining part of #193, which changes some interfaces.
Refactoring of the SEM types
AbstractLossis the base type for all functionsSemLoss{O,I} <: AbstractLossis the base type for all SEM losses, it now requires to have observed::O and implied::I fieldSemLossctor should always be given observed and implied (positional),meanstructurekeyword is gone -- loss should always respect implied specification.LossTermis a thin wrapper aroundAbstractLossthat adds optional id of the loss term and optional weightSemis a container ofLossTermobjects (accessible vialoss_terms(sem), orloss_term(sem, id)), so it can handle multiple SEM terms (accessible viasem_terms(sem)-- subset ofloss_terms(sem), orsem_term(sem, id)).It replaces both the old
SemandSemEnsemble.AbstractSingleSem,AbstractSemCollectionandSemEnsembleare gone.Method changes
Multi-term SEMs could be created like
Or with weights specification
The new Sem() and loss-term constructors rely less on keyword arguments and more on positional arguments, but some keywords support is present.
update_observed!()was removed. It was only used byreplace_observed(),but otherwise in-place model modification with unclear semantics is error-prone.
replace_observed(sem, data)was simplified by removing support of additional keywords or requirement to pass SEM specification.It only creates a copy of the given
Semwith the observed data replaced,but implied and loss definitions intact.
Changing observed vars is not supported -- that is something use-case specific
that user should implement in their code.
check_single_lossfun()was renamed intocheck_same_semterm_type()asit better describes what it does. If check is successful, it returns the specific
subtype of
SemLoss.bootstrap()andse_bootstrap()usebootstrap!(acc::BootstrapAccumulator, ...)function to reduce code duplication
bootstrap()returnsBootstrapResult{T}for better type inferencefit_measures()now also accepts vector of functions, and includesCFIby default (DEFAULT_FIT_MEASURESconstant)test_fitmeasures()was tweaked to handle more repetitive code: calculating the subset of fit measures, and compairing this subset against lavaan refs, checking for measures that could not be applied to given loss types (SemWLS).