codex/reliability-diagram-bin-merging.py

reliability-diagram-bin-merging.py
"""Synthetic calibration example; Python 3.14.4 / Matplotlib 3.10.7.

Run from the desired output directory. No training data or artwork is used.
"""
from pathlib import Path

import matplotlib.pyplot as plt


def main():
    scores = [.2] * 10 + [.8] * 10
    labels = [1] * 8 + [0] * 2 + [1] * 2 + [0] * 8
    groups = [list(range(10)), list(range(10, 20))]
    fine = [(sum(scores[i] for i in g)/len(g),
             sum(labels[i] for i in g)/len(g), len(g)) for g in groups]
    coarse = [(sum(scores)/20, sum(labels)/20, 20)]
    assert all(abs(x-a) < 1e-12 and abs(y-b) < 1e-12 and n == 10
               for (x, y, n), (a, b) in zip(fine, ((.2, .8), (.8, .2))))
    assert abs(coarse[0][0]-.5) < 1e-12 and coarse[0][1] == .5
    plt.rcParams.update({"font.family": "DejaVu Sans", "font.size": 11})
    fig, axes = plt.subplots(1, 2, figsize=(10, 4.9), dpi=135,
                             facecolor="white", sharey=True)
    for ax, data, title in zip(axes, (fine, coarse),
                               ("Two bins: [0, 0.5), [0.5, 1]", "One bin: [0, 1]")):
        ax.plot([0, 1], [0, 1], "--", color="#7c8991", lw=1.3)
        for x, y, n in data:
            ax.scatter([x], [y], s=100 if n == 10 else 180,
                       color="#a34329" if n == 10 else "#166783", zorder=3)
            ax.annotate(f"({x:.1f}, {y:.1f}), n={n}", (x, y),
                        xytext=(0, 12), textcoords="offset points", ha="center")
        ax.set(xlim=(-.03, 1.03), ylim=(-.03, 1.03), title=title,
               xlabel="Mean predicted positive probability")
        ax.set_aspect("equal")
        ax.grid(alpha=.15)
    axes[0].set_ylabel("Observed positive fraction")
    fig.suptitle("Same 20 predictions; different binning", fontsize=17, weight="bold")
    fig.text(.5, .025, "Synthetic outcomes: 8/10 positives at score 0.2; 2/10 at score 0.8. No population guarantee is inferred.",
             ha="center", fontsize=10)
    fig.tight_layout(rect=(0, .07, 1, .91))
    fig.savefig(Path.cwd() / (Path(__file__).stem + ".png"), facecolor="white")
    plt.close(fig)


if __name__ == "__main__":
    main()