npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

forecast-calibration-kit

v0.1.2

Published

Calibration metrics for probabilistic forecasts: Brier score, log loss, reliability diagram, Expected Calibration Error (ECE) and the Murphy decomposition of the Brier score. Zero runtime dependencies, strict TypeScript, with a CLI.

Readme

forecast-calibration-kit

CI npm version Coverage License: MIT

Calibration metrics for probabilistic (binary) forecasts, in TypeScript. Score how good your probabilities are and, crucially, whether they mean what they say: Brier score, log loss, calibration curve (reliability diagram), Expected Calibration Error (ECE), and the Murphy decomposition of the Brier score into reliability, resolution and uncertainty.

  • Zero runtime dependencies.
  • Strict TypeScript, fully typed public API, ships ESM and CommonJS builds.
  • Input validation at the boundary with clear, actionable errors.
  • A small CLI for scoring a JSON dataset straight from the terminal.

Why this exists

Probabilistic forecasting is everywhere — weather, prediction markets, credit risk, sports, and the probability outputs of machine-learning classifiers. This library provides a small, dependency-free TypeScript toolkit for scoring how good those probabilities are: Brier score, log loss, calibration curve (reliability diagram), Expected Calibration Error, and the Murphy (1973) decomposition of the Brier score into reliability, resolution and uncertainty — plus a CLI for scoring a dataset without writing any code.

Installation

npm install forecast-calibration-kit

Requires Node.js 18 or newer. Works in both ESM and CommonJS projects.

Quick start

import {
  brierScore,
  logLoss,
  calibrationCurve,
  expectedCalibrationError,
  brierDecomposition,
} from 'forecast-calibration-kit';

// Each sample pairs a forecast probability `p` in [0, 1] with a binary outcome (0 or 1).
const samples = [
  { p: 0.9, outcome: 1 },
  { p: 0.8, outcome: 1 },
  { p: 0.3, outcome: 0 },
  { p: 0.6, outcome: 1 },
  { p: 0.2, outcome: 0 },
];

brierScore(samples); // 0.068 — mean squared error, lower is better
logLoss(samples); // 0.2838 — log score / cross-entropy, lower is better
expectedCalibrationError(samples, { bins: 5 }); // 0.24 — gap between confidence and reality

calibrationCurve(samples, { bins: 5 });
// [{ binMidpoint, meanPredicted, observedFrequency, count }, ...]

brierDecomposition(samples, { bins: 5 });
// { reliability, resolution, uncertainty }

CommonJS works too:

const { brierScore } = require('forecast-calibration-kit');

API

All functions take a non-empty array of Sample objects ({ p: number /* [0,1] */, outcome: 0 | 1 }) and throw a CalibrationError if the input is empty or malformed (p out of range, outcome not 0/1, invalid options).

brierScore(samples): number

Mean squared error between forecast probabilities and outcomes: BS = (1/N) · Σ (pᵢ − outcomeᵢ)². Range [0, 1]; lower is better.

logLoss(samples, opts?): number

Logarithmic loss (binary cross-entropy): LL = −(1/N) · Σ [outcomeᵢ·ln(pᵢ) + (1 − outcomeᵢ)·ln(1 − pᵢ)]. Probabilities are clamped to [eps, 1 − eps] (default eps = 1e-15, configurable) so confident-but-wrong forecasts get a large finite penalty instead of Infinity. Lower is better.

calibrationCurve(samples, opts?): CalibrationBin[]

Groups forecasts into bins equal-width probability bins (default 10) and returns, for each non-empty bin, the mean forecast (meanPredicted) and the observed frequency of positives (observedFrequency). Plot observedFrequency against meanPredicted to draw a reliability diagram; a perfectly calibrated forecaster lies on the diagonal. Empty bins are omitted.

expectedCalibrationError(samples, opts?): number

Sample-weighted average gap between confidence and observed frequency across bins: ECE = Σ (countᵦ / N) · |meanPredictedᵦ − observedFrequencyᵦ|. Range [0, 1]; 0 means every bin is perfectly calibrated. Lower is better.

brierDecomposition(samples, opts?): { reliability, resolution, uncertainty }

The Murphy (1973) decomposition of the Brier score:

brierScore = reliability − resolution + uncertainty
  • reliability — mean squared gap between forecast and observed frequency per bin (calibration error; lower is better).
  • resolution — how much bin outcome frequencies vary around the base rate (discrimination; higher is better).
  • uncertaintybaseRate · (1 − baseRate), the intrinsic variance of the outcome; a property of the data, not of the forecasts.

The identity holds exactly when forecasts are constant within each bin and approximately otherwise (the gap is the within-bin variance of the forecasts, which shrinks as bins grows) — the standard behaviour of the binned Brier decomposition.

Choosing a metric

| Metric | Answers | Notes | | ----------------------- | --------------------------------------------------- | -------------------------------------------------------------------------------------- | | Brier score | How far are probabilities from outcomes overall? | Bounded [0, 1], interpretable, penalises quadratically. A good default. | | Log loss | How surprised is the forecaster? | Penalises confident mistakes far more harshly; unbounded. Common for ML training/eval. | | ECE | Do stated probabilities match observed frequencies? | Pure calibration; ignores discrimination. Depends on the number of bins. | | Calibration curve | Where is the forecaster over/under-confident? | Diagnostic, not a single number. Feeds a reliability diagram. | | Brier decomposition | Why is the Brier score what it is? | Separates calibration (reliability) from discrimination (resolution). |

Brier score and log loss are proper scoring rules: they are optimised by reporting your true beliefs. Use Brier for a bounded, robust overall score; use log loss when confident errors should be punished hard; use ECE and the calibration curve when you specifically care about whether "70%" really happens 70% of the time.

CLI

Score a JSON dataset without writing any code. Input is a JSON array of { "p": <0..1>, "outcome": <0|1> }, read from a file argument or from stdin.

# From a file
npx forecast-calibration-kit data.json

# From stdin
echo '[{"p":0.9,"outcome":1},{"p":0.2,"outcome":0}]' | npx forecast-calibration-kit

# Options
npx forecast-calibration-kit data.json --bins 5 --format json

Options:

| Flag | Description | Default | | ----------------- | --------------------------------------------- | ------- | | --bins <n> | Number of probability bins for calibration | 10 | | --format <fmt> | Output format: table or json | table | | --eps <e> | Probability clamp for log loss, in (0, 0.5) | 1e-15 | | -h, --help | Show help | | | -v, --version | Show version | |

Example table output:

Forecast calibration report
===========================
Samples:    20
Base rate:  0.6000

Metric                        Value
--------------------------------------
Brier score                   0.1974
Log loss                      0.5775
Expected calibration error    0.0965

Brier decomposition (Brier = reliability - resolution + uncertainty)
  reliability                 0.0147
  resolution                  0.0608
  uncertainty                 0.2400

Calibration curve (5 non-empty bin(s))
  bin mid   mean pred   obs freq    count
  ---------------------------------------
  0.1000    0.1000      0.0000      2
  ...

The CLI exits 0 on success, 1 on a data error (unreadable file, invalid JSON, out-of-range values), and 2 on a usage error (unknown flag, no input).

Contributing

Contributions are welcome — see CONTRIBUTING.md for how to set up the project, run the checks, and open a pull request.

License

MIT © Donizeti Ferreira