Functions¶
compare¶
compare(*models: Any, method: str = 'auto', sort: bool = True, test: str = 'chisq', refit: bool = False, cv: int | str = 5, seed: int | None = None, metric: str = 'mse', digits: int | None = None, holdout_group: str | None = None) -> pl.DataFrameCompare nested statistical models.
Performs sequential hypothesis tests comparing nested models. The appropriate test method is inferred from model type:
lm: F-test (equivalent to R’s anova())
glm: Deviance test (chi-squared)
lmer/glmer: Likelihood ratio test
cv: Cross-validation with Nadeau-Bengio corrected t-test
Cross-type comparisons (e.g., glm vs glmer) are supported when models share the same family. The fixed-only model is treated as nested within the mixed model via zero variance components.
| Model Pair | Hypothesis Test | AIC/BIC | CV |
|---|---|---|---|
| lm vs lm | F-test | Yes | Yes |
| glm vs glm | Deviance | Yes | Yes |
| lmer vs lmer | LRT | Yes | Yes |
| glmer vs glmer | LRT | Yes | Yes |
| lm vs lmer | LRT | Yes | Yes |
| glm vs glmer | LRT | Yes | Yes |
| Different families | — | Yes | Yes |
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
*models | Any | Two or more fitted model objects. | () |
method | str | Comparison method. Options: - “auto”: Infer from model type (default) - “f”: F-test (for lm) - “lrt”: Likelihood ratio test (for mixed models) - “deviance”: Deviance test (for glm) - “cv”: Cross-validation comparison (any model type) - “aic”: AIC comparison with delta-AIC and Akaike weights - “bic”: BIC comparison with delta-BIC and Schwarz weights | ‘auto’ |
sort | bool | If True, sort models by complexity before comparing. This ensures proper nesting order. Default True. | True |
refit | bool | If True and models are lmer/glmer with REML estimation, automatically refit with ML for valid LRT comparison. Original models are not mutated. Default False. Note: REML models are accepted without refitting when all models share the same fixed effects (valid for comparing random effects structures only). | False |
test | str | For GLM deviance comparisons only. Options: - “chisq”: Chi-squared test (default) - “f”: F-test (for quasi-families with estimated dispersion) | ‘chisq’ |
cv | int | str | For CV comparison only. Number of folds or “loo” for leave-one-out. | 5 |
seed | int | None | For CV comparison only. Random seed for reproducible splits. | None |
metric | str | For CV comparison only. Error metric (“mse”, “rmse”, “mae”). | ‘mse’ |
digits | int | None | Number of significant figures for float columns. Default None uses the global setting from set_display_digits() (4 by default). Pass 0 to disable rounding entirely. | None |
Returns:
| Type | Description |
|---|---|
DataFrame | DataFrame with comparison results. Columns depend on method: |
DataFrame | For F-test (lm): - model: Formula string - PRE: Proportional reduction in error - F: F-statistic - rss: Residual sum of squares - ss: Sum of squares explained - df: Degrees of freedom for comparison - df_resid: Residual degrees of freedom - p_value: p-value |
DataFrame | For deviance test (glm): - model: Formula string - chi2 (or F): Test statistic - dev_diff: Deviance reduction - deviance: Residual deviance - df: Degrees of freedom for comparison - df_resid: Residual degrees of freedom - p_value: p-value |
DataFrame | For LRT (lmer/glmer): - model: Formula string - chi2: Likelihood ratio chi-squared statistic - npar: Number of parameters - AIC: Akaike Information Criterion - BIC: Bayesian Information Criterion - loglik: Log-likelihood - deviance: Deviance (-2 * loglik) - df: Degrees of freedom for comparison - p_value: p-value |
DataFrame | For CV comparison: - model: Formula string - PRE: Proportional reduction in error - t_stat: Corrected t-statistic - cv_score: Mean CV error - cv_se: Standard error of CV error - diff: Difference from reference (first model) - diff_se: Nadeau-Bengio corrected standard error - p_value: Two-sided p-value |
DataFrame | For AIC/BIC comparison: - model: Formula string - npar: Number of estimated parameters - loglik: Log-likelihood - deviance: Deviance (-2 * loglik) - AIC/BIC: Information criteria - delta_AIC/delta_BIC: Difference from best model - weight: Akaike/Schwarz weight (model probability) |
Examples:
from bossanova import model, compare, load_dataset
mtcars = load_dataset("mtcars")
sleepstudy = load_dataset("sleepstudy")
# Models are auto-fitted if needed (calls .fit() with defaults)
compare(model("mpg ~ 1", mtcars), model("mpg ~ wt", mtcars))
# Equivalent to explicit .fit() calls:
compare(model("mpg ~ 1", mtcars).fit(), model("mpg ~ wt", mtcars).fit())
# Model objects are fitted in-place, so they're usable after compare()
compact = model("mpg ~ 1", mtcars)
full = model("mpg ~ wt", mtcars)
compare(compact, full)
full.params # Works - model was auto-fitted
# glm example (deviance test)
compare(
model("am ~ 1", mtcars, family="binomial"),
model("am ~ wt", mtcars, family="binomial"),
)
# lmer example (likelihood ratio test)
compare(
model("Reaction ~ Days + (1|Subject)", sleepstudy).fit(method="ML"),
model("Reaction ~ Days + (Days|Subject)", sleepstudy).fit(method="ML"),
)
# CV example (Nadeau-Bengio corrected)
compare(
model("mpg ~ 1", mtcars),
model("mpg ~ wt", mtcars),
method="cv", cv=5, seed=42,
)Notes: For single-parameter comparisons in lm models: F = t^2 where t is the t-statistic for the added parameter. This identity is fundamental and verified in parity tests.
For GLM, the deviance difference follows a chi-squared distribution: chi2 = deviance_compact - deviance_augmented with df = df_compact - df_augmented degrees of freedom.
For mixed models (lmer/glmer), the LRT statistic is:
chi2 = 2 * (loglik_augmented - loglik_compact)
with df = npar_augmented - npar_compact degrees of freedom.
REML models are accepted when all models share the same fixed
effects (comparing random effects structures only). Otherwise,
ML estimation is required — use refit=True to auto-refit.
A warning is emitted when any model has singular (boundary) variance components, as the chi-squared p-values may be conservative. See Self & Liang (1987).
For CV comparison, the Nadeau-Bengio correction accounts for overlapping training sets in k-fold CV: var_corrected = var(diff) * (1/k + n_test/n_train) This prevents the underestimation of variance that occurs with naive paired t-tests on CV folds.
See Also:
lrt: Likelihood ratio test for mixed models
load_dataset¶
load_dataset(name: DatasetName) -> pl.DataFrameLoad a sample dataset as a Polars DataFrame.
Datasets are bundled with the package and loaded directly from package resources. No network access required.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name | DatasetName | Name of the dataset to load. Use show_datasets() to see available options. | required |
Returns:
| Type | Description |
|---|---|
DataFrame | The requested dataset as a Polars DataFrame. |
Examples:
from bossanova.data import load_dataset
# Load sleep study data for mixed models
sleep = load_dataset("sleep")
print(sleep.head())
# Load mtcars for regression examples
mtcars = load_dataset("mtcars")show_datasets¶
show_datasets() -> pl.DataFrameShow available datasets with descriptions.
Returns:
| Type | Description |
|---|---|
DataFrame | DataFrame with columns: name, description. |
Examples:
from bossanova.data import show_datasets
show_datasets()
# shape: (12, 2)
# ┌───────────────┬─────────────────────────────────┐
# │ name ┆ description │
# │ --- ┆ --- │
# │ str ┆ str │
# ╞═══════════════╪═════════════════════════════════╡
# │ sleep ┆ Sleep study data (reaction ... │
# │ mtcars ┆ Motor Trend Car Road Tests ... │
# │ ... ┆ ... │
# └───────────────┴─────────────────────────────────┘to_markdown¶
to_markdown(df: pl.DataFrame, path: str | Path | None = None, caption: str | None = None) -> strConvert a Polars DataFrame to a markdown table, optionally saving to file.
Standalone utility for DataFrames not wrapped in ModelResult —
such as results from compare(), model.jointtest(),
model.vif(), model.to_odds_ratio(), etc.
For ModelResult objects (returned by .fit(), .infer(),
etc.), use result.to_markdown() instead.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
df | DataFrame | Polars DataFrame to convert. | required |
path | str | Path | None | Optional file path. If given, writes the markdown and creates parent directories automatically. | None |
caption | str | None | Optional table caption (Table: ... Quarto syntax). | None |
Returns:
| Type | Description |
|---|---|
str | Pipe-delimited markdown table as a string. |
Examples:
>>> from bossanova import compare, to_markdown
>>> to_markdown(compare(m1, m2), "comparison.md", caption="Model Comparison")
>>> md = to_markdown(m.jointtest()) # string only