Repeated-measures analysis requires a different data layout and, usually, a different estimand. The wide-data matrix workflow is not enough because the analysis must account for the repeated structure within subject.
This vignette covers:
rmcorr()ba_rm()ccc_rm_ustat()ccc_rm_reml()icc_rm_reml()Repeated-measures functions use a subject argument for
the subject identifier role, including rmcorr(),
ba_rm(), ccc_rm_ustat(),
ccc_rm_reml(), and icc_rm_reml().
library(matrixCorr)
set.seed(50)
n_id <- 14
n_time <- 4
dat <- expand.grid(
id = factor(seq_len(n_id)),
time = factor(seq_len(n_time)),
method = factor(c("A", "B"))
)
dat$time_index <- as.integer(dat$time)
subj <- rnorm(n_id, sd = 1.0)[dat$id]
subject_method <- rnorm(n_id * 2, sd = 0.25)
sm <- subject_method[(as.integer(dat$id) - 1L) * 2L + as.integer(dat$method)]
subject_time <- rnorm(n_id * n_time, sd = 0.75)
st <- subject_time[(as.integer(dat$id) - 1L) * n_time + as.integer(dat$time)]
dat$y <- subj + sm + st + 0.35 * (dat$method == "B") +
rnorm(nrow(dat), sd = 0.35)rmcorr() targets within-subject association, not
agreement. It is the right function when the question is whether two
responses vary together within subjects after removing subject-level
offsets.
set.seed(51)
dat_rmcorr <- data.frame(
id = rep(seq_len(n_id), each = n_time),
x = rnorm(n_id * n_time),
y = rnorm(n_id * n_time),
z = rnorm(n_id * n_time)
)
dat_rmcorr$y <- 0.7 * dat_rmcorr$x +
rnorm(n_id, sd = 1)[dat_rmcorr$id] +
rnorm(nrow(dat_rmcorr), sd = 0.3)
fit_rmcorr <- rmcorr(dat_rmcorr, response = c("x", "y", "z"), subject = "id")
summary(fit_rmcorr)
#> Correlation summary
#> output : matrix
#> dimensions : 3 x 3
#> retained_pairs: 6
#> threshold : 0.0000
#> diag : included
#> estimate : -0.3995 to 1.0000
#>
#> item1 item2 estimate n_complete fisher_z
#> x y 0.9397 56 1.7356
#> y z -0.3995 56 -0.4230
#> x z -0.3843 56 -0.4051
#>
#> Strongest pairs by |estimate|
#>
#> item1 item2 estimate n_complete fisher_z
#> x y 0.9397160 56 1.7356154
#> y z -0.3994915 56 -0.4230437
#> x z -0.3843429 56 -0.4051453Agreement methods require method labels and, for paired repeated analysis, a time or replicate key.
ba_rm() is the repeated-measures Bland-Altman route. It
models subject-time matched paired differences and returns bias and
limits of agreement.
fit_ba_rm <- ba_rm(
dat,
response = "y",
subject = "id",
method = "method",
time = "time_index"
)
summary(fit_ba_rm)
#>
#> Bland-Altman (two methods) (95% CI)
#>
#> Agreement estimates
#>
#> item1 item2 n_obs bias sd_loa loa_low loa_up width
#> method 1 method 2 56 0.654 0.651 -0.622 1.93 2.552
#>
#> Confidence intervals
#>
#> bias_lwr bias_upr lo_lwr lo_upr up_lwr up_upr
#> 0.483 0.824 -0.793 -0.452 1.759 2.101
#>
#> Model details
#>
#> sigma2_subject sigma2_resid residual_model
#> 0 0.424 iidThe package provides two repeated-measures CCC routes.
ccc_rm_ustat() is a nonparametric U-statistic
approach.ccc_rm_reml() uses the REML mixed-model backend.fit_ccc_ustat <- ccc_rm_ustat(
dat,
response = "y",
subject = "id",
method = "method",
time = "time_index"
)
fit_ccc_reml <- ccc_rm_reml(
dat,
response = "y",
subject = "id",
method = "method",
time = "time_index",
ci = FALSE
)
summary(fit_ccc_ustat)
#> Lin's concordance summary
#> method : Repeated-measures Lin's concordance
#> dimensions : 2 x 2
#> pairs : 1
#> estimate : 0.7180
#> most_negative: A-B (0.7180)
#> most_positive: A-B (0.7180)
#>
#> Strongest pairs by |estimate|
#>
#> item1 item2 estimate
#> A B 0.718
summary(fit_ccc_reml)
#>
#> Repeated-measures concordance (REML)
#>
#> Concordance estimates
#>
#> item1 item2 estimate n_subjects n_obs SB se_ccc
#> A B 0.6542 14 112 0.2047 0.0607
#>
#> Variance components
#>
#> sigma2_subject sigma2_subject_method sigma2_subject_time sigma2_error
#> 0.4785 0.0997 0.5943 0.1085
#>
#> AR(1) diagnostics
#>
#> ar1_rho ar1_rho_lag1 ar1_rho_mom ar1_pairs ar1_pval use_ar1 ar1_recommend
#> -0.3941 -0.3941 -0.3941 84 3e-04 FALSE FALSEThe two functions are related, but they are not interchangeable. The U-statistic route is useful when its design assumptions are appropriate. The REML route is the more flexible model-based path when variance components and residual structure need to be handled explicitly.
icc_rm_reml() uses the same REML and Woodbury backend as
repeated CCC, but it targets a different reliability quantity.
fit_icc_cons <- icc_rm_reml(
dat,
response = "y",
subject = "id",
method = "method",
time = "time_index",
type = "consistency",
ci = TRUE
)
fit_icc_agr <- icc_rm_reml(
dat,
response = "y",
subject = "id",
method = "method",
time = "time_index",
type = "agreement",
ci = FALSE
)
summary(fit_icc_cons)
#>
#> Repeated-measures intraclass correlation (REML) (95% CI)
#>
#> ICC estimates
#>
#> item1 item2 estimate lwr upr n_subjects n_obs se_icc residual_model
#> A B 0.6347 0.63 0.64 14 112 0.0022 iid
#>
#> Variance components
#>
#> sigma2_subject sigma2_subject_method sigma2_subject_time sigma2_error SB
#> 0.4785 0.0997 0.5943 0.1085 0.2047
#>
#> AR(1) diagnostics
#>
#> ar1_rho_lag1 ar1_rho_mom ar1_pairs ar1_pval use_ar1 ar1_recommend
#> -0.3941 -0.3941 84 3e-04 FALSE FALSE
summary(fit_icc_agr)
#>
#> Repeated-measures intraclass correlation (REML)
#>
#> ICC estimates
#>
#> item1 item2 estimate n_subjects n_obs se_icc residual_model
#> A B 0.4992 14 112 0.0463 iid
#>
#> Variance components
#>
#> sigma2_subject sigma2_subject_method sigma2_subject_time sigma2_error SB
#> 0.4785 0.0997 0.5943 0.1085 0.2047
#>
#> AR(1) diagnostics
#>
#> ar1_rho_lag1 ar1_rho_mom ar1_pairs ar1_pval use_ar1 ar1_recommend
#> -0.3941 -0.3941 84 3e-04 FALSE FALSEThe simulation above gives the subject-time component a visibly non-trivial variance contribution. That makes the CCC-versus-ICC distinction easier to see:
data.frame(
method = c("Repeated CCC (REML)", "Repeated ICC (agreement, REML)"),
estimate = c(
fit_ccc_reml[1, 2],
fit_icc_agr[1, 2]
)
)
#> method estimate
#> 1 Repeated CCC (REML) 0.6541643
#> 2 Repeated ICC (agreement, REML) 0.4991620The most important distinction between repeated CCC and repeated ICC is the numerator. Repeated ICC uses only the stable between-subject variance in the numerator. Repeated CCC also credits the time-averaged subject-time component. As a result, the two summaries can differ materially even when they are fitted through the same backend.
The method choice should follow the scientific question.
rmcorr() for within-subject association.ba_rm() for repeated-measures bias and limits of
agreement.ccc_rm_ustat() or ccc_rm_reml() for
repeated concordance.icc_rm_reml() for repeated reliability under a
variance-components interpretation.The shared long-format interface is intentional. The statistical targets are different, but the package keeps the surrounding workflow stable.