Skip to content

Plot score distributions

Auditor.plot_score_distributions() operates directly on registered data, features, and a score. Combined plots do not require an outcome, selected metrics, or a completed metric evaluation.

Terminal window
python -m pip install matplotlib
from model_auditor import Auditor
auditor = Auditor()
auditor.add_data(data)
auditor.add_feature(name="region", label="Region")
auditor.add_feature(name="age_group", label="Age group")
auditor.add_score(name="risk_score", label="Risk score")

A score threshold is optional for this plot because it visualizes continuous values.

plots = auditor.plot_score_distributions(
score_name="risk_score",
bins=30,
density=True,
split_classes=False,
)

For each feature, the method creates one vertically stacked histogram per observed level. Every level in a feature uses the same bin edges, computed from that feature’s complete non-null score slice.

fig, axes = plots["region"]
fig.savefig(
"region-score-distributions.png",
dpi=180,
bbox_inches="tight",
)

With density=True, each level’s histogram integrates to approximately one. This compares distribution shape but does not preserve relative subgroup size.

Use counts instead:

count_plots = auditor.plot_score_distributions(
score_name="risk_score",
density=False,
split_classes=False,
)
plots = auditor.plot_score_distributions(
score_name="risk_score",
feature_names=["age_group", "region"],
bins="fd",
split_classes=False,
)

The dictionary follows the requested feature order. String bin strategies are forwarded to NumPy’s histogram-bin calculation.

Categorical feature columns follow declared category order among observed levels:

data["age_group"] = pd.Categorical(
data["age_group"],
categories=["18–39", "40–59", "60–79", "80+"],
ordered=True,
)

Unobserved categories are omitted from score-distribution figures even though they remain as NaN placeholder rows in metric tables.

Plain non-categorical values follow first-appearance order in this plotting method.

Rows are removed from a feature’s figure when either that feature value or the score is null. If no rows remain, the method raises ValueError.

This filtering is specific to score-distribution plotting and does not imply that ordinary metric evaluation globally removes score or outcome nulls.

Register a binary outcome, then request overlaid negative and positive histograms:

auditor.add_outcome("outcome")
plots = auditor.plot_score_distributions(
score_name="risk_score",
split_classes=True,
)

With density enabled, each nonempty class is normalized separately. Class splitting rejects missing or nonbinary outcomes. The default is False, which preserves one combined histogram per level.

dict[
str,
tuple[
matplotlib.figure.Figure,
numpy.ndarray,
],
]

The axes array always has one dimension, including a one-level feature.

See Plotting API for validation errors and defaults.