Log Loss
Install and import#
npm install fintech-algorithmsimport { logLoss } from "fintech-algorithms/model-validation-and-backtesting/classification-and-score-validation/log-loss";Signature#
logLoss(inputs)Computes the weighted mean negative log likelihood of a set of probability forecasts, clipping each probability into [epsilon, 1 - epsilon] first and reporting how many forecasts the clip actually moved.
Parameters#
| Name | Type | Notes |
|---|---|---|
inputs | { records: Array<{ id: string; label: 0 | 1; probability: number; weight?: number; score_available_at?: string; label_available_at?: string }>; evaluation_cutoff?: string; epsilon?: number } | The forecast population plus the clipping floor. Every record needs a unique nonempty id, a label that is exactly the number 0 or 1, and a finite probability in [0,1]; weight defaults to 1 and must be positive. epsilon defaults to 1e-15 and must sit strictly inside (0,0.5). If evaluation_cutoff is supplied, any score_available_at or label_available_at on a record is compared against it as a string and must not sort after it.probability: between 0 and 1 inclusive · weight: positive, default 1 · epsilon: strictly between 0 and 0.5, default 1e-15 |
Returns#
{ log_loss: number; clipped_count: number; epsilon: number; weight_sum: number; event_rate: number; state: string }
log_loss is the weight-normalised loss, clipped_count the number of records whose probability the clip changed, epsilon the floor actually applied, weight_sum the total weight, event_rate the weighted positive share, and state is probability-evaluated.
Errors#
- When
recordsis absent, not an array, or empty — throws RangeError - When a record
idis missing, empty, or repeats an earlier one — throws RangeError - When a
labelis anything other than the number 0 or 1 — throws RangeError - When a
probabilityfalls outside [0,1] — throws RangeError - When a
weightis zero or negative — throws RangeError - When
epsilonis not strictly inside (0,0.5) — throws RangeError - When a record
probability,weight, orepsilonis not a finite number — throws TypeError - When
score_available_atorlabel_available_atsorts afterevaluation_cutoff— throws RangeError
Complexity: time O(n),
space O(n).
Worked example#
verified This is the worked example published in the article, replayed by the test suite on every run. The output cannot drift.
Input#
{
"records": [
{
"id": "R01",
"label": 1,
"score": 0.95,
"probability": 0.92,
"weight": 1,
"sector": "Banking",
"country": "Egypt",
"regime": "Expansion",
"score_available_at": "2025-01-01T00:00:00Z",
"label_available_at": "2026-01-01T00:00:00Z"
},
{
"id": "R02",
"label": 0,
"score": 0.9,
"probability": 0.88,
"weight": 1,
"sector": "Insurance",
"country": "Egypt",
"regime": "Expansion",
"score_available_at": "2025-01-01T00:00:00Z",
"label_available_at": "2026-01-01T00:00:00Z"
},
{
"id": "R03",
"label": 1,
"score": 0.9,
"probability": 0.84,
"weight": 1,
"sector": "Markets",
"country": "Saudi Arabia",
"regime": "Expansion",
"score_available_at": "2025-01-01T00:00:00Z",
"label_available_at": "2026-01-01T00:00:00Z"
}
],
"evaluation_cutoff": "2026-06-30T00:00:00Z",
"epsilon": 1e-15
}Call#
logLoss(inputs)Returns#
object with 6 fields: log_loss, clipped_count, epsilon, weight_sum, event_rate, state
{
"log_loss": 0.7086022750977335,
"clipped_count": 0,
"epsilon": 1e-15,
"weight_sum": 24,
"event_rate": 0.4166666666666667,
"state": "probability-evaluated"
}Other exports#
This module also exports
rocCurveAndRocAuc, precisionRecallCurveAndPrAuc, brierScore, reliabilityDiagramAndExpectedCalibrationError, gainsLiftAndDecileCapture, costSensitiveThresholdOptimization, scoreStabilityAndMigrationMatrix, sliceBasedValidationBySectorCountryAndRegime, rareEventBacktestAndConfidenceBounds, calculate. Every module additionally exports run as an alias of its
primary function, and a meta object carrying its catalog id, domain, family,
shape and article URL.
Diagrams#
Calculation flow#
Log Loss calculation flow
flowchart LR
S1["Validate probability label weight cutoff and epsilon"]
S2["Clip each probability to the declared open interval"]
S3["Select the observed class probability"]
S4["Take its negative natural logarithm"]
S5["Weight and average"]
S1 --> S2
S2 --> S3
S3 --> S4
S4 --> S5
S5 --> D{"endpoint clipping must remain explicit and countable"}
D --> O["log_loss + diagnostics"]
O --> A["Audit: Log loss is nonnegative and equals zero only in the unatta"]
How it works#
This page states the contract — how to call it correctly. The article explains the concept: why it works, and where it breaks.
References#
- Revised Guidance on Model Risk Management — Board of Governors of the Federal Reserve System, OCC, and FDIC
- Rational Decisions — I. J. Good
- Metrics and scoring: quantifying the quality of predictions — scikit-learn maintainers
- Evidence boundary