11.1 Ordered categorical outcomes
Ordered categorical outcomes, such as Likert scales, have a natural order but no fixed spacing. Cumulative link models assume that a latent continuous variable is cut into categories by thresholds.
11.1.1 The cumulative link model
The idea: there is a latent continuous variable that determines the response. The observed category is determined by where falls relative to cutpoints :
where is the linear predictor. The cutpoints are estimated from the data.
# Ordered categorical (cumulative link) model
# Simulate Likert-scale data (1-7 response)
set.seed(42)
n <- 300
# Latent continuous variable
x <- runif(n, 0, 10)
phi <- -1 + 0.3 * x + rnorm(n, sd = 1)
# Cutpoints for 7 categories (6 cutpoints)
cutpoints <- c(-2, -1, 0, 1, 2, 3)
# Convert to ordered categories
y <- cut(phi, breaks = c(-Inf, cutpoints, Inf), labels = 1:7)
y <- as.numeric(as.character(y))
cat("Ordered categorical data:\n")
cat(" Categories:", paste(sort(unique(y)), collapse = ", "), "\n")
cat(" Distribution:", paste(table(y), collapse = ", "), "\n")
# Fit ordered logistic regression using MASS::polr
library(MASS)
m <- polr(factor(y) ~ x, method = "logistic")
cat("\nOrdered logistic regression:\n")
cat(" Coefficient:", round(coef(m)[1], 3), "\n")
cat(" Cutpoints:", round(m$zeta, 3), "\n")
# Predicted probabilities at x = 2, 5, 8
cat("\nPredicted probabilities:\n")
for (x_val in c(2, 5, 8)) {
pred <- predict(m, data.frame(x = x_val), type = "prob")
cat(sprintf(" x = %d: P(y=1)=%.3f P(y=4)=%.3f P(y=7)=%.3f\n",
x_val, pred[1], pred[4], pred[7]))
}11.1.2 Interpreting the model
The coefficient tells us how the latent variable shifts per unit increase in . A positive means higher shifts the distribution toward higher categories.
# Visualize the cumulative link model
set.seed(42)
n <- 300
x <- runif(n, 0, 10)
phi <- -1 + 0.3 * x + rnorm(n, sd = 1)
cutpoints <- c(-2, -1, 0, 1, 2, 3)
y <- as.numeric(cut(phi, breaks = c(-Inf, cutpoints, Inf), labels = 1:7))
library(MASS)
m <- polr(factor(y) ~ x, method = "logistic")
# Plot predicted category probabilities vs x
x_seq <- seq(0, 10, length.out = 200)
pred_matrix <- predict(m, data.frame(x = x_seq), type = "prob")
# Stacked area plot
par(mfrow = c(1, 1))
colors <- rainbow(7)
plot(NULL, xlim = c(0, 10), ylim = c(0, 1),
xlab = "x", ylab = "Probability",
main = "Cumulative link: category probabilities vs x")
for (k in 1:7) {
if (k == 1) {
polygon(c(x_seq, rev(x_seq)), c(pred_matrix[, k], rep(0, length(x_seq))),
col = adjustcolor(colors[k], 0.7), border = NA)
} else {
polygon(c(x_seq, rev(x_seq)),
c(rowSums(pred_matrix[, 1:k]), rev(rowSums(pred_matrix[, 1:(k-1)]))),
col = adjustcolor(colors[k], 0.7), border = NA)
}
}
legend("topright", legend = paste("y =", 1:7), fill = adjustcolor(colors, 0.7),
ncol = 4, cex = 0.8)
cat("As x increases, probability shifts toward higher categories.\n")
cat("The cutpoints determine where the shifts occur.\n")Ordered categories are not intervals. A Likert scale from 1 to 7 looks like numbers, but the distance between 1 and 2 is not necessarily the same as the distance between 6 and 7. The cumulative link model respects this: it assumes only the order, not the spacing. The cutpoints are estimated from the data, so the model learns where the boundaries are. This is more honest than treating ordered categories as continuous numbers, which assumes equal spacing — an assumption that is rarely justified.
Summary of Section 11.1
- Ordered categorical outcomes have order but no fixed spacing.
- Cumulative link model: a latent variable is cut into categories by thresholds.
- where .
- The coefficient shifts the latent variable; cutpoints are estimated.
- Use
MASS::polr()for ordered logistic regression in R.