Agreement of Continuous Measurements
Menu location: Analysis_Agreement_Continuous (Intra-class).
The function calculates one way random effects intra-class correlation coefficient, estimated within-subjects standard deviation and a repeatability coefficient (Bland and Altman 1996a and 1996b, Shrout and Fleiss 1979, McGraw and Wong 1996).
Intra-class correlation coefficient is calculated as:
- where m is the number of observations per subject, MSB is the between-subjects mean square and MSW is the within-subjects (residual) mean square from one way ANOVA. This is the one way random effects coefficient ICC(1) of Shrout and Fleiss (1979) and McGraw and Wong (1996). Its confidence interval is calculated from the exact distribution of F = MSB/MSW with n − 1 and n(m − 1) degrees of freedom, where n is the number of subjects:
- where FU and FL are the upper and lower α/2 quantiles of the F distribution with n − 1 and n(m − 1) degrees of freedom, for a 100(1 − α)% confidence interval.
Within-subjects standard deviation is estimated as the square root of the residual mean square from one way ANOVA.
The repeatability coefficient is calculated as:
- where z is a quantile from the standard normal distribution (usually taken as the 5% two tailed quantile of 1.96) and ζw is the estimated within-subjects standard deviation (calculated as above).
Intra-subject standard deviation is plotted against intra-subject means and Kendall's rank correlation is used to assess the interdependence of these two variables.
An agreement plot is constructed by plotting the maximum differences from each possible intra-subject contrast against intra-subject means and the overall mean is marked as a line on this plot.
A Q-Q plot is given; here the sum of the difference between intra-subject observations and their means are ordered and plotted against an equal order of chi-square quantiles.
Agreement analysis is best carried out under expert statistical guidance.
Example
From Bland and Altman (1996a).
Test workbook (Agreement worksheet: 1st, 2nd, 3rd, 4th).
Four peak flow measurements were repeated for twenty children:
| 1st | 2nd | 3rd | 4th |
| 190 | 220 | 200 | 200 |
| 220 | 200 | 240 | 230 |
| 260 | 260 | 240 | 280 |
| 210 | 300 | 280 | 265 |
| 270 | 265 | 280 | 270 |
| 280 | 280 | 270 | 275 |
| 260 | 280 | 280 | 300 |
| 275 | 275 | 275 | 305 |
| 280 | 290 | 300 | 290 |
| 320 | 290 | 300 | 290 |
| 300 | 300 | 310 | 300 |
| 270 | 250 | 330 | 370 |
| 320 | 330 | 330 | 330 |
| 335 | 320 | 335 | 375 |
| 350 | 320 | 340 | 365 |
| 360 | 320 | 350 | 345 |
| 330 | 340 | 380 | 390 |
| 335 | 385 | 360 | 370 |
| 400 | 420 | 425 | 420 |
| 430 | 460 | 480 | 470 |
To analyse these data using StatsDirect you must first enter them into a workbook or open the test workbook. Then select Continuous from the Agreement section of the Analysis menu.
Agreement
Variables: 1st, 2nd, 3rd, 4th
Intra-class correlation coefficient (one way random effects) = 0.887666 (95% CI = 0.795982 to 0.948056; F = MSB/MSW on 19 and 60 df)
Estimated within-subjects standard deviation = 21.459749
For within-subjects sd vs. mean, Kendall's tau b = 0.164457 two sided P = 0.3296
Repeatability (for alpha = 0.05) = 59.482297
Note that Bland and Altman (1996a) quote an intra-class correlation of 0.88 for these data, from Fisher's symmetrical-table form of the coefficient; the one way random effects (ANOVA) estimator above gives 0.89.
R code
This R code reproduces the example above. It needs no packages and was checked with R 4.6.1. Paste it into R, or save it as a script and run it.
# Agreement of continuous measurements: the StatsDirect help example (Bland and Altman
# 1996a, four peak flow readings on each of 20 children; the test workbook's Agreement
# worksheet columns 1st to 4th) in R
first <- c(190, 220, 260, 210, 270, 280, 260, 275, 280, 320, 300, 270, 320, 335, 350,
360, 330, 335, 400, 430)
second <- c(220, 200, 260, 300, 265, 280, 280, 275, 290, 290, 300, 250, 330, 320, 320,
320, 340, 385, 420, 460)
third <- c(200, 240, 240, 280, 280, 270, 280, 275, 300, 300, 310, 330, 330, 335, 340,
350, 380, 360, 425, 480)
fourth <- c(200, 230, 280, 265, 270, 275, 300, 305, 290, 290, 300, 370, 330, 375, 365,
345, 390, 370, 420, 470)
flow <- cbind(first, second, third, fourth)
n <- nrow(flow)
m <- ncol(flow)
# R's standard one way analysis of variance of the readings by child: its between
# children and residual (within children) mean squares give the one way random
# effects intra-class correlation and the within-subjects standard deviation
long <- data.frame(reading = as.vector(flow), child = factor(rep(1:n, m)))
a <- anova(lm(reading ~ child, data = long))
print(a)
# The report's lines to 6 places. The interval for the coefficient comes from the F
# distribution of MSB/MSW on n - 1 and n(m - 1) degrees of freedom
six <- function(x) formatC(x, digits = 6, format = "f", drop0trailing = TRUE)
pv <- function(p) {
if (p < 0.0001) "P < 0.0001" else
paste("P =", formatC(p, digits = 4, format = "f", drop0trailing = TRUE))
}
msb <- a["child", "Mean Sq"]
msw <- a["Residuals", "Mean Sq"]
icc <- (msb - msw) / (msb + (m - 1) * msw)
f <- msb / msw
fu <- qf(0.975, n - 1, n * (m - 1))
fl <- qf(0.025, n - 1, n * (m - 1))
cat("Intra-class correlation coefficient (one way random effects) =", six(icc),
"(95% CI =", six((f / fu - 1) / (f / fu + m - 1)), "to",
six((f / fl - 1) / (f / fl + m - 1)), ")\n")
sw <- sqrt(msw)
cat("Estimated within-subjects standard deviation =", six(sw), "\n")
# Each child's standard deviation against the child's mean: Kendall's tau b, with the
# continuity corrected normal approximation to its P value (the ties rule out the
# exact test)
child_sd <- apply(flow, 1, sd)
child_mean <- rowMeans(flow)
kt <- cor.test(child_sd, child_mean, method = "kendall", exact = FALSE,
continuity = TRUE)
cat("For within-subjects sd vs. mean, Kendall's tau b =", six(kt$estimate),
" two sided", pv(kt$p.value), "\n")
# The repeatability coefficient: for 95% of pairs of readings on the same child, the
# two readings differ by less than root 2 times 1.96 times the within-subjects
# standard deviation
cat("Repeatability (for alpha = 0.05) =", six(sqrt(2) * qnorm(0.975) * sw), "\n")
# The report's three plots: each child's standard deviation, then the largest
# difference between two of the child's readings, against the child's mean; and the
# ordered sums of the absolute deviations of each child's readings from their mean
# against chi-square quantiles on m - 1 degrees of freedom
largest <- apply(flow, 1, function(r) {
d <- outer(r, r, "-")[upper.tri(diag(m))]
d[which.max(abs(d))]
})
par(mfrow = c(1, 3))
plot(child_mean, child_sd, xlab = "subject mean", ylab = "subject standard deviation",
main = "Repeatability Plot")
plot(child_mean, largest, xlab = "subject mean", ylab = "largest difference",
main = "Agreement Plot")
abline(h = mean(largest), lty = 2)
plot(qchisq(seq(0.01, 0.99, length.out = n), m - 1),
sort(rowSums(abs(flow - child_mean))), xlab = paste0("chi-square (", m - 1, ")"),
ylab = "Sum(|x-mean(x)|)", main = "Q-Q Plot")