Residuals

Extract marginal or conditional residuals from a fitted model. Works with both CrossedLMEResult and statsmodels.MixedLMResults.

hlm_resid(model, full_data=True, type='marginal', standardized=False, level=1)[source]

Extract residuals from a fitted linear mixed model.

Parameters:
  • model – A CrossedLMEResult or statsmodels MixedLMResults object.

  • full_data – If True, prepend the original data columns to the result.

  • type"marginal" (ignoring random effects, y - ) or "conditional" (subtracting predicted random effects, y - - Zu). Only used when level=1.

  • standardized – If True, divide residuals by sqrt(scale).

  • level1 for observation-level residuals; a factor/group name for group-level random effects.

Return type:

Any

Returns:

Native DataFrame in the same type as the model’s input data.

Parameters:
  • model (Any)

  • full_data (bool)

  • type (str)

  • standardized (bool)

  • level (int | str)

Examples

>>> resid_df = interlace.hlm_resid(result, type="conditional")
>>> resid_df[[".resid", ".fitted"]].head()

Residual types

Type

Formula

Interpretation

Conditional

y Xβ̂ Zb̂

Within-group unexplained variation; accounts for BLUPs

Marginal

y Xβ̂

Between- and within-group unexplained variation; ignores BLUPs

Use conditional residuals to check within-group model fit (normality, homoscedasticity). Use marginal residuals to assess the overall fit including random-effect structure.

Example

import interlace
import matplotlib.pyplot as plt
import numpy as np

result = interlace.fit("rt ~ condition", data=df, groups=["subject", "item"])

resid_df = interlace.hlm_resid(result)
print(resid_df.columns.tolist())
# ['resid.conditional', 'resid.marginal', 'fitted.conditional', 'fitted.marginal']

# Check normality of conditional residuals
resid_df["resid.conditional"].plot.hist(bins=30, edgecolor="white")
plt.xlabel("Conditional residual")
plt.title("Distribution of conditional residuals")
plt.show()

# Residual vs fitted (conditional)
resid_df.plot.scatter(x="fitted.conditional", y="resid.conditional", alpha=0.4)
plt.axhline(0, linestyle="--", color="grey")
plt.title("Residuals vs Fitted (conditional)")
plt.show()

See also