Source code for qp.metrics.brier
import logging
import numpy as np
[docs]class Brier:
"""Brier score based on https://en.wikipedia.org/wiki/Brier_score#Original_definition_by_Brier
Parameters
----------
prediction: NxM array, float
Predicted probability for N distributions to have a true value in
one of M bins. The sum of values along each row N should be 1.
truth: NxM array, int
True values for N distributions, where Mth bin for the
true value will have value 1, all other bins will have a value of
0.
"""
def __init__(self, prediction, truth):
"""Constructor"""
self._prediction = prediction
self._truth = truth
self._axis_for_summation = None # axis to sum for metric calculation
[docs] def evaluate(self):
"""Evaluate the Brier score.
Returns
-------
float
The result of calculating the Brier metric, a value in the interval [0,2]
"""
self._manipulate_data()
self._validate_data()
return self._calculate_metric()
def accumulate(self):
self._manipulate_data()
self._validate_data()
return self._calculate_metric_for_accumulation()
def _manipulate_data(self):
"""
Placeholder for data manipulation as required. i.e. converting from
qp.ensemble objects into np.array objects.
"""
# Attempt to convert the input variables into np.arrays
self._prediction = np.array(self._prediction)
self._truth = np.array(self._truth)
def _validate_data(self):
"""
Strictly for data validation - no calculations or data structure
changes.
Raises
------
TypeError if either prediction or truth input could not be converted
into a numeric Numpy array
ValueError if the prediction and truth arrays do not have the same
numpy.shape.
Warning
-------
Logs a warning message if the input predictions do not each sum to 1.
"""
# Raise TypeError exceptions if the inputs were not translated to
# numeric np.arrays
if not np.issubdtype(self._prediction.dtype, np.number):
raise TypeError(
"Input prediction array could not be converted to a Numpy array"
)
if not np.issubdtype(self._truth.dtype, np.number):
raise TypeError("Input truth array could not be converted to a Numpy array")
# Raise ValueError if the arrays have different shapes
if self._prediction.shape != self._truth.shape:
raise ValueError(
"Input prediction and truth arrays do not have the same shape"
)
# Log a warning if the N rows of the input prediction do not each sum to
# 1. Note: For 1d arrays, a sum along axis = 1 will fail, so we set
# self._axis_for_summation appropriately for that case
self._axis_for_summation = 0 if self._prediction.ndim == 1 else 1
if not np.allclose(
np.sum(self._prediction, axis=self._axis_for_summation), 1.0
):
logging.warning("Input predictions do not sum to 1.")
def _calculate_metric(self):
"""
Calculate the Brier metric for the input data.
"""
return np.mean(
np.sum((self._prediction - self._truth) ** 2, axis=self._axis_for_summation)
)
def _calculate_metric_for_accumulation(self):
return np.sum(
np.sum((self._prediction - self._truth) ** 2, axis=self._axis_for_summation)
)