TensorFlow
Matthews Correlation Coefficient
MCC Calculation
Machine Learning
Data Science

How do I calculate the matthews correlation coefficient in tensorflow

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Matthews correlation coefficient, or MCC, is a strong binary-classification metric when class imbalance makes accuracy misleading. It uses all four confusion-matrix terms, so it penalizes one-sided predictions much more honestly than plain accuracy. In TensorFlow, the safest implementation is a stateful metric that accumulates confusion counts across batches and computes MCC from the totals.

Start from the MCC Formula

For binary classification:

MCC = ((tp * tn) - (fp * fn)) / sqrt((tp + fp) * (tp + fn) * (tn + fp) * (tn + fn))

The result ranges from -1 to 1:

  • '1 means perfect agreement'
  • '0 is roughly no useful correlation'
  • '-1 means systematic disagreement'

Because the formula depends on the full confusion matrix, you should not compute MCC independently per batch and then average those batch scores. That produces the wrong answer in general.

Implement MCC as a Stateful Keras Metric

The cleanest TensorFlow pattern is to store running totals of tp, tn, fp, and fn.

python
1import tensorflow as tf
2
3
4class MatthewsCorrelationCoefficient(tf.keras.metrics.Metric):
5    def __init__(self, name="mcc", threshold=0.5, **kwargs):
6        super().__init__(name=name, **kwargs)
7        self.threshold = threshold
8        self.tp = self.add_weight(name="tp", initializer="zeros")
9        self.tn = self.add_weight(name="tn", initializer="zeros")
10        self.fp = self.add_weight(name="fp", initializer="zeros")
11        self.fn = self.add_weight(name="fn", initializer="zeros")
12
13    def update_state(self, y_true, y_pred, sample_weight=None):
14        y_true = tf.cast(tf.reshape(y_true, [-1]), tf.float32)
15        y_pred = tf.cast(tf.reshape(y_pred, [-1]) >= self.threshold, tf.float32)
16
17        self.tp.assign_add(tf.reduce_sum(y_true * y_pred))
18        self.tn.assign_add(tf.reduce_sum((1.0 - y_true) * (1.0 - y_pred)))
19        self.fp.assign_add(tf.reduce_sum((1.0 - y_true) * y_pred))
20        self.fn.assign_add(tf.reduce_sum(y_true * (1.0 - y_pred)))
21
22    def result(self):
23        numerator = (self.tp * self.tn) - (self.fp * self.fn)
24        denominator = tf.sqrt(
25            (self.tp + self.fp)
26            * (self.tp + self.fn)
27            * (self.tn + self.fp)
28            * (self.tn + self.fn)
29        )
30        return tf.where(denominator > 0.0, numerator / denominator, 0.0)
31
32    def reset_state(self):
33        for variable in self.variables:
34            variable.assign(0.0)

This metric expects binary labels and probability-like predictions that can be thresholded.

Test the Metric Before Training

Always verify the metric on a tiny deterministic example before wiring it into a model.

python
1metric = MatthewsCorrelationCoefficient(threshold=0.5)
2
3y_true = tf.constant([1, 0, 1, 1, 0, 0], dtype=tf.float32)
4y_pred = tf.constant([0.9, 0.2, 0.7, 0.4, 0.1, 0.8], dtype=tf.float32)
5
6metric.update_state(y_true, y_pred)
7print(float(metric.result().numpy()))

That simple sanity check catches threshold mistakes and shape issues early.

Use It in model.compile

Once the implementation is behaving correctly, you can register it like any other Keras metric.

python
1model = tf.keras.Sequential([
2    tf.keras.layers.Input(shape=(20,)),
3    tf.keras.layers.Dense(32, activation="relu"),
4    tf.keras.layers.Dense(1, activation="sigmoid"),
5])
6
7model.compile(
8    optimizer="adam",
9    loss="binary_crossentropy",
10    metrics=[MatthewsCorrelationCoefficient(threshold=0.5)],
11)

This is especially useful for imbalanced problems such as fraud detection, anomaly detection, and medical screening.

Threshold Choice Is Part of the Metric Behavior

MCC is computed on binary decisions, not raw probabilities. That means the threshold is not a small implementation detail. It materially changes the score.

A common workflow is:

  1. train with probabilistic outputs
  2. evaluate MCC across several thresholds on validation data
  3. keep the threshold that matches the operating tradeoff you want

If you blindly hard-code 0.5, you may be measuring the model at the wrong operating point.

Handle Degenerate Cases Explicitly

The denominator becomes zero when one side of the confusion matrix is missing entirely, such as all predictions being one class. That is why the metric uses:

python
tf.where(denominator > 0.0, numerator / denominator, 0.0)

Without that guard, you can get NaN results and unstable training logs.

Common Pitfalls

  • Averaging per-batch MCC instead of accumulating global confusion counts first.
  • Forgetting to threshold probabilistic predictions before computing tp, tn, fp, and fn.
  • Ignoring the zero-denominator case and producing NaN.
  • Reusing the binary version for multi-class problems without redesigning the metric.
  • Treating the threshold as fixed by theory rather than a tunable operating choice.

Summary

  • MCC is a useful binary-classification metric for imbalanced datasets.
  • In TensorFlow, implement it as a stateful metric that accumulates confusion counts across batches.
  • Compute MCC from global tp, tn, fp, and fn, not from averaged batch scores.
  • Threshold predicted probabilities before counting outcomes.
  • Guard against zero denominators and tune the threshold on validation data when needed.

Course illustration
Course illustration

All Rights Reserved.