-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add postposterior covariance matrix based mirt rules * Qualify usage of even_grid in dt test * Formatting of ability_estimator * Add todo note to comparison.jl * Refactor dispersion around ScalarizedStateCriteron * Apply formatting
- Loading branch information
Showing
10 changed files
with
348 additions
and
108 deletions.
There are no files selected for viewing
This file contains 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
This file contains 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
This file contains 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
This file contains 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
This file contains 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
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
#= | ||
This file contains some specialised ways to calculate information. | ||
For some models analytical solutions are possible for information. | ||
Most are simple applications of the chain rule | ||
However, I haven't taken a systematic approach yet yet. | ||
So these are just from equations in the literature. | ||
There aren't really any type guards on these so its up to the caller to make sure they are using the right ones. | ||
=# | ||
|
||
function alt_expected_1d_item_information(ir::ItemResponse, θ) | ||
""" | ||
This is a special case of the expected_item_information function for | ||
* 1-dimensional ability | ||
* Dichotomous items | ||
* It should be valid for at least up to the 3PL model, probably others too | ||
TODO: citation | ||
""" | ||
# irθ_prime = ForwardDiff.derivative(ir, θ) | ||
irθ_prime = ForwardDiff.derivative(x -> resp(ir, x), θ) | ||
irθ = resp(ir, θ) | ||
if irθ_prime == 0.0 | ||
return 0.0 | ||
else | ||
return (irθ_prime * irθ_prime) / (irθ * (1 - irθ)) | ||
end | ||
end | ||
|
||
function alt_expected_mirt_item_information(ir::ItemResponse, θ) | ||
""" | ||
This is a special case of the expected_item_information function for | ||
* Multidimensional | ||
* Dichotomous items | ||
* It should be valid for at least up to the 3PL model, probably others too | ||
TODO: citation | ||
""" | ||
irθ_prime = ForwardDiff.gradient(x -> resp(ir, x), θ) | ||
pθ = resp(ir, θ) | ||
qθ = 1 - pθ | ||
(irθ_prime * irθ_prime') / (pθ * qθ) | ||
end | ||
|
||
function alt_expected_mirt_3pl_item_information(ir::ItemResponse, θ) | ||
""" | ||
This is a special case of the expected_item_information function for | ||
* Multidimensional | ||
* Dichotomous items | ||
* 3PL model only | ||
Mulder J, van der Linden WJ. | ||
Multidimensional Adaptive Testing with Optimal Design Criteria for Item Selection. | ||
Psychometrika. 2009 Jun;74(2):273-296. doi: 10.1007/s11336-008-9097-5. | ||
Equation 4 | ||
""" | ||
# XXX: Should avoid using item_params | ||
params = item_params(ir.item_bank.discriminations, ir.index) | ||
pθ = resp(ir, θ) | ||
qθ = 1 - pθ | ||
a = params.discrimination | ||
c = params.guess | ||
common_factor = (qθ * (pθ - c)^2) / (pθ * (1 - c)^2) | ||
common_factor * (a * a') | ||
end |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
abstract type MatrixScalarizer end | ||
|
||
struct DeterminantScalarizer <: MatrixScalarizer end | ||
(::DeterminantScalarizer)(mat) = det(mat) | ||
|
||
struct TraceScalarizer <: MatrixScalarizer end | ||
(::TraceScalarizer)(mat) = tr(mat) | ||
|
||
abstract type StateCriteria end | ||
abstract type ItemCriteria end | ||
|
||
struct AbilityCovarianceStateCriteria{ | ||
DistEstT <: DistributionAbilityEstimator, | ||
IntegratorT <: AbilityIntegrator | ||
} <: StateCriteria | ||
dist_est::DistEstT | ||
integrator::IntegratorT | ||
skip_zero::Bool | ||
end | ||
|
||
function AbilityCovarianceStateCriteria(bits...) | ||
skip_zero = false | ||
@requiresome (dist_est, integrator) = _get_dist_est_and_integrator(bits...) | ||
return AbilityCovarianceStateCriteria(dist_est, integrator, skip_zero) | ||
end | ||
|
||
# XXX: Should be at type level | ||
should_minimize(::AbilityCovarianceStateCriteria) = true | ||
|
||
function (criteria::AbilityCovarianceStateCriteria)( | ||
tracked_responses::TrackedResponses, | ||
denom = normdenom(criteria.integrator, | ||
criteria.dist_est, | ||
tracked_responses) | ||
) | ||
if denom == 0.0 && criteria.skip_zero | ||
return Inf | ||
end | ||
covariance_matrix( | ||
criteria.integrator, | ||
criteria.dist_est, | ||
tracked_responses, | ||
denom | ||
) | ||
end | ||
|
||
struct ScalarizedStateCriteron{ | ||
StateCriteriaT <: StateCriteria, | ||
MatrixScalarizerT <: MatrixScalarizer | ||
} <: StateCriterion | ||
criteria::StateCriteriaT | ||
scalarizer::MatrixScalarizerT | ||
end | ||
|
||
function (ssc::ScalarizedStateCriteron)(tracked_responses) | ||
res = ssc.criteria(tracked_responses) |> ssc.scalarizer | ||
if !should_minimize(ssc.criteria) | ||
res = -res | ||
end | ||
res | ||
end | ||
|
||
struct InformationMatrixCriteria{AbilityEstimatorT <: AbilityEstimator, F} <: ItemCriteria | ||
ability_estimator::AbilityEstimatorT | ||
expected_item_information::F | ||
end | ||
|
||
function InformationMatrixCriteria(ability_estimator) | ||
InformationMatrixCriteria(ability_estimator, expected_item_information) | ||
end | ||
|
||
function init_thread(item_criterion::InformationMatrixCriteria, | ||
responses::TrackedResponses) | ||
# TODO: No need to do this one per thread. It just need to be done once per | ||
# θ update. | ||
# TODO: Update this to use track!(...) mechanism | ||
ability = maybe_tracked_ability_estimate(responses, item_criterion.ability_estimator) | ||
responses_information(responses.item_bank, responses.responses, ability) | ||
end | ||
|
||
function (item_criterion::InformationMatrixCriteria)(acc_info::Matrix{Float64}, | ||
tracked_responses::TrackedResponses, | ||
item_idx) | ||
# TODO: Add in information from the prior | ||
ability = maybe_tracked_ability_estimate( | ||
tracked_responses, item_criterion.ability_estimator) | ||
return acc_info .+ | ||
item_criterion.expected_item_information( | ||
ItemResponse(tracked_responses.item_bank, item_idx), ability) | ||
end | ||
|
||
should_minimize(::InformationMatrixCriteria) = false | ||
|
||
struct ScalarizedItemCriteron{ | ||
ItemCriteriaT <: ItemCriteria, | ||
MatrixScalarizerT <: MatrixScalarizer | ||
} <: ItemCriterion | ||
criteria::ItemCriteriaT | ||
scalarizer::MatrixScalarizerT | ||
end | ||
|
||
function (ssc::ScalarizedItemCriteron)(tracked_responses, item_idx) | ||
res = ssc.criteria( | ||
init_thread(ssc.criteria, tracked_responses), tracked_responses, item_idx) |> | ||
ssc.scalarizer | ||
if !should_minimize(ssc.criteria) | ||
res = -res | ||
end | ||
res | ||
end | ||
|
||
struct WeightedStateCriteria{InnerT <: StateCriteria} <: StateCriteria | ||
weights::Vector{Float64} | ||
criteria::InnerT | ||
end | ||
|
||
function (wsc::WeightedStateCriteria)(tracked_responses, item_idx) | ||
wsc.weights' * wsc.criteria(tracked_responses, item_idx) * wsc.weights | ||
end | ||
|
||
struct WeightedItemCriteria{InnerT <: ItemCriteria} <: ItemCriteria | ||
weights::Vector{Float64} | ||
criteria::InnerT | ||
end | ||
|
||
function (wsc::WeightedItemCriteria)(tracked_responses, item_idx) | ||
wsc.weights' * wsc.criteria(tracked_responses, item_idx) * wsc.weights | ||
end |
Oops, something went wrong.