The hardware and bandwidth for this mirror is donated by METANET, the Webhosting and Full Service-Cloud Provider.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]metanet.ch.
The Prowise Learn algorithm (Vermeiren et al., 2025) extends the
Elo-style Maths Garden updates
(vignette("maths-garden-update")) with paired item
updates that counteract rating drift — the tendency for item
difficulty estimates to slide systematically over time.
Abilities are updated exactly as in Maths Garden:
\[\theta_j^{new} = \theta_j + K_\theta \sum_{i \in I_j} (S_{ij} - E(S_{ij})).\]
Item difficulties, however, are updated in consecutive pairs of items administered to the same respondent. For a pair (previous item, current item),
\[\kappa = 0.5\,\big(K_b (S_{now} - E_{now}) - K_b (S_{prev} - E_{prev})\big), \qquad b_{now} \mathrel{+}= \kappa, \quad b_{prev} \mathrel{-}= \kappa.\]
Because each pair adds \(+\kappa\) to one item and \(-\kappa\) to the other, the total difficulty mass is conserved, so items keep their relative positions and do not drift en masse. Expected responses use the Rasch model, \(E(S_{ij}) = 1 / (1 + e^{-(\theta_j - b_i)})\).
meowPaired updates are inherently order dependent, so
update_prowise_learn() uses
meow_long(R, admin), which returns the administered
responses ordered by respondent and then by administration order.
Consecutive within-respondent rows form the pairs; the per-item
contributions are aggregated with tapply():
update_prowise_learn <- function(pers, item, R, admin, K_theta = 0.1, K_b = 0.1) {
long <- meow_long(R, admin)
E_Sij <- stats::plogis(pers$theta[long$id] - item$b[long$item])
# ability update (as in Maths Garden)
dtheta <- tapply(long$resp - E_Sij, long$id, sum)
pers$theta[as.integer(names(dtheta))] <-
pers$theta[as.integer(names(dtheta))] + K_theta * dtheta
# paired item updates over consecutive administrations
n <- nrow(long)
if (n >= 2) {
nxt <- 2:n; prv <- 1:(n - 1)
pair <- which(long$id[nxt] == long$id[prv])
if (length(pair) > 0) {
now <- nxt[pair]; pre <- prv[pair]
kappa <- 0.5 * (K_b * (long$resp[now] - E_Sij[now]) -
K_b * (long$resp[pre] - E_Sij[pre]))
add_now <- tapply(kappa, long$item[now], sum)
add_pre <- tapply(-kappa, long$item[pre], sum)
item$b[as.integer(names(add_now))] <- item$b[as.integer(names(add_now))] + add_now
item$b[as.integer(names(add_pre))] <- item$b[as.integer(names(add_pre))] + add_pre
}
}
list(pers = pers, item = item)
}sim <- meow(
select_fun = select_max_info,
update_fun = update_prowise_learn,
data_loader = data_simple_1pl,
data_args = list(N_persons = 100, N_items = 50),
update_args = list(K_theta = 0.05, K_b = 0.05)
)
head(sim$results[, 1:3])
#> iter pers_theta_1_est pers_theta_2_est
#> 1 1 0.1250000 -0.1250000
#> 2 2 0.2656826 -0.2657371
#> 3 3 0.3692123 -0.3715956
#> 4 4 0.4806109 -0.4711769
#> 5 5 0.5559021 -0.6101828
#> 6 6 0.6200887 -0.7172594admin carries the order of
administration.These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.