Home Accueil / Blog / Statistics Statistiques

Handling quasi-complete separation in CLMM:
a practical guide

Gérer la quasi-séparation complète dans CLMM :
un guide pratique

TL;DR

Quasi-complete separation occurs when a predictor perfectly or near-perfectly predicts an outcome category. The model will run, but the estimates are unreliable, often inflated to extreme values with huge standard errors. Here is how to detect it, understand it, and handle it correctly.

À quoi ressemble la quasi-séparation complète

La quasi-séparation complète est un problème de configuration des données, pas une erreur de code. Elle survient quand un prédicteur prédit quasi-parfaitement l'outcome. Dans les petites études cosmétiques avec de nombreux temps de mesure, certaines combinaisons temps-traitement auront très peu d'observations, et les catégories extrêmes de l'échelle seront vides pour certains groupes.

Détection : signes d'alerte dans la sortie R

library(ordinal)

model <- clmm(
  score_ord ~ treatment * visit + (1 | subject_id),
  data = study_data
)

summary(model)
# Signes d'alerte : coefficients > 10, erreurs standard > 5
# Vérification directe :
table(study_data$treatment, study_data$visit, study_data$score_ord)
# Cherchez les cellules entières de zéros

Régularisation bayésienne comme alternative

La solution la plus pratique pour la quasi-séparation dans les modèles ordinaux est l'estimation bayésienne avec des priors faiblement informatifs. Le prior agit comme un régulariseur qui empêche les estimations de diverger vers l'infini.

library(brms)

model_bayes <- brm(
  score_ord ~ treatment * visit + (1 | subject_id),
  data   = study_data,
  family = cumulative("logit"),
  prior  = c(
    prior(normal(0, 2.5), class = "b"),
    prior(normal(0, 5),   class = "Intercept")
  ),
  chains = 4, iter = 2000, seed = 42
)
summary(model_bayes)

Regrouper les catégories : quand et comment

Quand la séparation survient dans des catégories extrêmes, regrouper des catégories adjacentes est une solution plus simple. Le regroupement doit être pré-spécifié dans le plan d'analyse si vous l'anticipez. Le regroupement post-hoc est une analyse de sensibilité, pas l'analyse primaire.

Rapporter quand la séparation survient

Notez que la quasi-séparation a été observée, décrivez où elle s'est produite, et rapportez à la fois le résultat de l'analyse primaire et l'analyse de sensibilité avec l'estimation pénalisée ou bayésienne. Un OR gonflé avec un grand ES n'est pas un résultat: c'est un diagnostic.


À retenir

La quasi-séparation complète est courante dans les petites études ordinales et n'est pas une erreur de code. Diagnostiquez-la avec des tables de contingence, gérez-la avec des priors bayésiens ou le regroupement de catégories, et rapportez-la de manière transparente avec une analyse de sensibilité.

What quasi-complete separation looks like

Quasi-complete separation is a data configuration problem, not a coding error. It occurs when one predictor, or a combination of predictors, almost perfectly predicts the outcome. In ordinal regression, it typically manifests when all subjects with a certain treatment or characteristic fall into the extreme categories of the scale, leaving no overlap with the other group in the middle categories.

Example: in a small cosmetic study with 20 panelists, suppose all panelists in the active treatment group achieve a score of 4 (maximum improvement) at day 56, while all placebo panelists score 0-2. The model tries to estimate an odds ratio for "treatment at day 56 vs baseline" and finds the data perfectly consistent with an infinite OR. The maximum likelihood estimate does not exist in the usual sense.

Why it happens in small cosmetic/clinical studies

Small sample sizes with many time points are the primary risk factor. With 20-30 subjects and 4 time points, some time-treatment combinations will have very few observations. Late time points in successful trials are especially prone: if the treatment works well, most treated subjects will be in the top category by week 8, and the lower categories will be empty for that group.

Ordinal scales with few categories are also at risk: a 4-point scale with 30 subjects means each cell in your treatment × time × outcome contingency table has very few observations.

Detection: warning signs in R output

The ordinal package will often converge but give you inflated estimates:

library(ordinal)

model <- clmm(
  score_ord ~ treatment * visit + (1 | subject_id),
  data = study_data
)

summary(model)
# Warning signs:
# 1. Coefficient estimates > 10 in absolute value for a treatment term
# 2. Standard errors > 5 for those same terms
# 3. Very wide confidence intervals: exp(coef - 1.96*SE) to exp(coef + 1.96*SE)
# 4. Warning message: "Model may not have converged"

# Check for separation directly
table(study_data$treatment, study_data$visit, study_data$score_ord)
# Look for cells with all zeros - this is separation

The three-way table is the definitive diagnostic. If you see entire rows or columns of zeros, you have separation in that subset.

Penalized likelihood: the Firth approach

The standard solution for logistic regression is the Firth penalized likelihood. For ordinal models, it is less directly available, but can be approximated. The key idea: add a penalty to the likelihood function that shrinks extreme estimates toward zero.

# For binary outcomes (if you collapse ordinal to binary for sensitivity):
library(logistf)

model_firth <- logistf(
  response_binary ~ treatment + visit,
  data = study_data
)

# For ordinal: Bayesian regularization is more practical (see next section)

Bayesian regularization as an alternative

The most practical solution for quasi-complete separation in ordinal models is Bayesian estimation with weakly informative priors. The prior acts as a regularizer that prevents estimates from diverging to infinity.

library(brms)

model_bayes <- brm(
  score_ord ~ treatment * visit + (1 | subject_id),
  data   = study_data,
  family = cumulative("logit"),
  prior  = c(
    prior(normal(0, 2.5), class = "b"),  # shrink coefficients toward 0
    prior(normal(0, 5),   class = "Intercept")
  ),
  chains = 4, iter = 2000, seed = 42
)

summary(model_bayes)
# Posterior median and credible intervals for treatment effects

With priors centered at 0 with moderate variance, the model will not estimate infinite ORs. The posterior will be dominated by the prior in the separated cells and by the data in the non-separated cells.

Collapsing categories: when and how

A simpler solution when separation occurs in extreme categories is to collapse adjacent categories. If all treated subjects score 3 or 4, and you are trying to distinguish 3 from 4, consider whether that distinction is clinically or commercially meaningful.

# Collapse 4-point scale to 3-point: merge categories 0 and 1
study_data$score_collapsed <- dplyr::case_when(
  study_data$score_ord %in% c("0", "1") ~ "0-1",
  study_data$score_ord == "2" ~ "2",
  study_data$score_ord %in% c("3", "4") ~ "3-4"
)

# Refit model on collapsed scale
model_collapsed <- clmm(
  factor(score_collapsed) ~ treatment * visit + (1 | subject_id),
  data = study_data
)

Category collapsing should be pre-specified in the analysis plan if you anticipate it. Post-hoc collapsing is a sensitivity analysis, not the primary analysis.

Reporting when separation occurs

Transparency is essential. In the results section, note that quasi-complete separation was observed, describe where it occurred (which time-treatment combinations), and report both the primary analysis result (with the caveat about instability) and the sensitivity analysis using penalized or Bayesian estimation.

Do not simply report the inflated OR with a note that results should be interpreted with caution and leave it at that. A specific sensitivity analysis with a concrete alternative estimate gives the reader something to act on.


Key takeaway

Quasi-complete separation is common in small ordinal studies and is not a coding error. Diagnose it with contingency tables, handle it with Bayesian priors or category collapsing, and report it transparently with a sensitivity analysis. An inflated OR with a huge SE is not a result: it is a diagnostic.

AM

Aslane Mortreau

Freelance Data & AI specialist working with pharmaceutical, biotech, and cosmetic R&D teams. Statistical modeling, analytical pipelines, and custom applications.

Spécialiste Data & IA freelance travaillant avec des équipes R&D pharmaceutiques, biotech et cosmétiques. Modélisation statistique, pipelines analytiques et applications sur mesure.