Diagnostic curves for a single fitted model: ROC, precision-recall, and learning curves.
Where a metric collapses a model to one number, a curve shows the whole trade-off. This module covers the three curves worth plotting for most projects:
-
plot_roc_curve— true positive rate against false positive rate as the
-
plot_pr_curve— precision against recall over the same threshold
-
plot_learning_curve— train and validation score as the training set
All three take arrays you already have — no model is refitted here. Each calls matplotlib.pyplot.show() and optionally writes a PNG via save_path. matplotlib is imported lazily, so every function raises ImportError when it is missing.
Functions
Plot a Receiver Operating Characteristic curve, binary or one-vs-rest.
The curve traces true positive rate against false positive rate as the decision threshold sweeps from "predict nothing positive" (bottom left) to "predict everything positive" (top right). A perfect ranker hugs the top-left corner; the dashed diagonal is what random guessing achieves. The shaded area under the curve is the AUC, and equals the probability that a randomly chosen positive sample is scored higher than a randomly chosen negative one, so 0.5 is chance and 1.0 is perfect.
The plot is threshold-free — it says how well the model ranks, not how well any particular cut-off classifies. Because the false positive rate is normalised by the number of negatives, ROC stays optimistic on heavily imbalanced data; pair it with plot_pr_curve there.
Two modes are selected automatically from the shape of y_score. With a 1-D score vector (or a 2-column probability matrix, whose second column is used) a single binary curve is drawn. With a probability matrix of three or more columns, one one-vs-rest curve is drawn per class plus a dotted macro-average curve interpolated on a common 200-point FPR grid.
Parameters
y_true
y_score
predict_proba. Predicted labels will not produce a meaningful curve.
title
' (one-vs-rest)' is appended in the multiclass path.
figsize
save_path
show_auc
(AUC = ...) to the legend entry. Binary path only.
label
'ROC'. Binary path only.
show_grid
classes
y_score, used to label the per-class curves. Defaults to np.unique(y_true). Multiclass path only.
Returns
fpr
tpr
auc_score
Raises
ImportError
ValueError
y_true has more than two classes but y_score is 1-D, or if len(classes) does not match the number of y_score columns.
Notes
matplotlib.pyplot.show() before returning, and writes a file when save_path is given. The figure object is not returned. Use a non-interactive backend such as Agg for headless rendering.See Also
>>> import numpy as np
>>> from tuiml.evaluation.visualization import plot_roc_curve
>>> y_true = np.array([0, 0, 1, 1, 0, 1])
>>> y_score = np.array([0.1, 0.4, 0.35, 0.8, 0.2, 0.9])
>>> fpr, tpr, auc_score = plot_roc_curve(y_true, y_score) # doctest: +SKIP
Multiclass, straight from a fitted TuiML classifier:
>>> from tuiml.datasets import load_iris
>>> from tuiml.evaluation.splitting import train_test_split
>>> from tuiml.algorithms import NaiveBayesClassifier
>>> X, y = load_iris()
>>> X_train, X_test, y_train, y_test = train_test_split(
... X, y, test_size=0.3, random_state=0)
>>> clf = NaiveBayesClassifier().fit(X_train, y_train)
>>> proba = clf.predict_proba(X_test)
>>> fpr, tpr, macro_auc = plot_roc_curve(
... y_test, proba, classes=[0, 1, 2],
... save_path='roc.png') # doctest: +SKIP
Plot a precision-recall curve for a binary classifier.
Each point corresponds to one decision threshold: recall (x) is the fraction of true positives found, precision (y) is the fraction of positive predictions that were right. Lowering the threshold moves you right — more positives found — usually at the cost of precision, so the curve slopes down to the right. A model that is useful everywhere stays high across the whole width; a model that only works when it is very confident starts high and collapses.
The dashed horizontal baseline is the positive class prevalence, which is what a random classifier achieves. On imbalanced data that line sits low, which is exactly why this plot is more honest than ROC: beating it is a real achievement, and the gap above it is visible at a glance. The shaded area is summarised by the average precision (AP) reported in the legend.
Parameters
y_true
y_score
title
figsize
save_path
show_ap
(AP = ...) to the legend entry.
label
'PR'.
show_grid
Returns
recall
precision
ap
Raises
ImportError
Notes
The curve is evaluated at every distinct value in y_score, so cost is O(n^2) in the number of unique scores — subsample before plotting very large score vectors.
y_true must be 0/1: unlike plot_roc_curve, no binarisation of other label encodings is performed, and arbitrary labels silently yield an all-zero curve.
Side effects: mutates the global matplotlib style, calls matplotlib.pyplot.show() before returning, and writes a file when save_path is given. The figure object is not returned.
See Also
>>> import numpy as np
>>> from tuiml.evaluation.visualization import plot_pr_curve
>>> y_true = np.array([0, 0, 1, 1, 0, 1, 0, 0])
>>> y_score = np.array([0.1, 0.4, 0.35, 0.8, 0.2, 0.9, 0.05, 0.3])
>>> recall, precision, ap = plot_pr_curve(y_true, y_score) # doctest: +SKIP
Plot training and validation score as a function of training set size.
Two curves are drawn against the number of training samples: training score (circles) and cross-validation score (squares), each optionally with a \pm 1 standard deviation band across CV folds. This is the plot that tells you whether to collect more data or change the model:
- Validation curve still rising at the right edge — more data will help.
- Validation curve flat and a wide gap below the training curve —
- Both curves flat, close together and low — underfitting; the model is
Nothing is fitted here: you supply the sizes and the scores, typically collected by refitting an estimator on growing subsets and scoring each fit with a splitter from splitting.
Parameters
train_sizes
train_scores
test_scores
train_scores.
title
figsize
save_path
metric_name
'Accuracy').
show_std
show_grid
Returns
None
Raises
ImportError
Notes
matplotlib.pyplot.show(), and writes a file when save_path is given.See Also
>>> import numpy as np
>>> from tuiml.evaluation.visualization import plot_learning_curve
>>> train_sizes = np.array([20, 40, 60, 80, 100])
>>> train_scores = np.array([[0.99, 0.98, 1.00],
... [0.97, 0.97, 0.98],
... [0.96, 0.96, 0.97],
... [0.96, 0.95, 0.96],
... [0.95, 0.95, 0.96]])
>>> test_scores = np.array([[0.72, 0.70, 0.75],
... [0.80, 0.79, 0.82],
... [0.85, 0.84, 0.86],
... [0.88, 0.87, 0.88],
... [0.89, 0.89, 0.90]])
>>> plot_learning_curve(train_sizes, train_scores, test_scores,
... metric_name='Accuracy') # doctest: +SKIP