Creating Custom Metrics#
If there is an evaluation metric you want to use that is not provided by Brisk,
you can add it to your project by adding a MetricWrapper in metrics.py.
Note
For the MetricWrapper documentation, see the MetricWrapper API reference.
Defining a Metric Function#
The first step is to define a function that calculates the metric. This functions
must take two arguments, y_true and y_pred (in this order). These are array-like
objects of the same length with the actual and predicted values, respectively. Your metric
function should return a float. You can define these functions in the metrics.py file
before you create the MetricManager. You may also import functions that implement an
evaluation metric from scikit-learn or other libraries, given it follows the expected interface.
Here is an example of a metric function that calculates the concordance correlation coefficient:
import numpy as np
import scipy
def concordance_correlation_coefficient(y_true, y_pred):
corr, _ = scipy.stats.pearsonr(y_true, y_pred)
mean_true = np.mean(y_true)
mean_pred = np.mean(y_pred)
var_true = np.var(y_true)
var_pred = np.var(y_pred)
sd_true = np.std(y_true)
sd_pred = np.std(y_pred)
numerator = 2 * corr * sd_true * sd_pred
denominator = var_true + var_pred + (mean_true - mean_pred)**2
return numerator / denominator
There may be additional arguments that are required by your metric function and these
can be defined after the y_true and y_pred arguments.
Split Metadata#
You may encounter metric functions that require additional information about the data.
For example, the adjusted R2 score requires the number of features in the dataset.
Brisk provides a split_metadata argument that is passed to your metric function.
This dictionary contains a couple of values for the data split being used.
Key |
Value |
|---|---|
num_features |
The number of features in the dataset |
num_samples |
The number of samples in the dataset |
To use this metadata in your metric function, you can access the split_metadata
dictionary in your function.
from sklearn.metrics import _regression
def adjusted_r2_score(y_true, y_pred, split_metadata):
r2 = _regression.r2_score(y_true, y_pred)
adjusted_r2 = (1 - (1 - r2) * (len(y_true) - 1) /
(len(y_true) - split_metadata["num_features"] - 1))
return adjusted_r2
If you do not need to use the split metadata, you can ignore it in your function definition.
Multiclass Metrics#
Some metrics are defined for the binary classification problem and only consider the positive label.
When extending a binary metric to a multiclass problem, the problem is treated as a series of
binary classification problems for each class. These values need to be averaged to get a single
value for the metric for all classes. For sklearn metrics, this is done by passing the average
parameter as an argument to the MetricWrapper.
More details can be found in the scikit-learn documentation.
Create a MetricWrapper#
Once the metric function is defined we simply need to create a MetricWrapper
and add it to the MetricManager in metrics.py. Using the concordance correlation coefficient metric
function from the previous section, we can create the following MetricWrapper:
METRIC_CONFIG = brisk.MetricManager(
brisk.MetricWrapper(
name="concordance_correlation_coefficient",
func=concordance_correlation_coefficient,
display_name="Concordance Correlation Coefficient",
abbr="CCC"
)
)
The name and abbr atttributes must be unique as they are used to identify the metric.
You can name them whatever makes sense for your project. The display_name attribute is
used in plots and tables to identify the metric.
By adding the MetricWrapper to the MetricManager, the metric will be available for use
in your workflows.