Как рассчитать коэффициент корреляции Мэтьюса в тензорном потоке

Итак, я сделал модель с tensorflow keras, и, похоже, она работает нормально. Однако мой руководитель сказал, что было бы полезно рассчитать коэффициент корреляции Мэтьюза, а также точность и потери, которые он уже рассчитывает.

моя модель очень похожа на код в туториале (https://www.tensorflow.org/tutorials/keras/basic_classification), за исключением гораздо меньшего набора данных.

есть ли готовая функция или мне нужно будет получить прогноз для каждого теста и рассчитать его вручную?


person Toby Peterken    schedule 03.07.2019    source источник


Ответы (4)


Готовая функция для расчета коэффициента корреляции Мэтью

sklearn.metrics.matthews_corrcoef(y_true, y_pred, sample_weight=None )

пример :

> from sklearn.metrics import matthews_corrcoef
> y_true = [+1, +1, +1, -1]
> y_pred = [+1, -1, +1, +1]
> matthews_corrcoef(y_true, y_pred) 

См. документацию.

person pallavi sangapu - Intel    schedule 12.07.2019
comment
но это не вычисляет его в тензорном потоке - person Stewart_R; 09.08.2019
comment
@Stewart_R вот и все (требуется Tensorflow 2): tensorflow.org/addons /api_docs/python/tfa/metrics/ - person ledawg; 11.04.2020

Нет ничего готового, но мы можем рассчитать его по формуле в пользовательской метрике.

Предоставленная вами базовая ссылка на классификацию предназначена для задачи категоризации с несколькими классами, тогда как коэффициент корреляции Мэтьюса предназначен специально для задач бинарной классификации.

Предполагая, что ваша модель структурирована «нормальным» образом для таких проблем (т. Е. y_pred - это число от 0 до 1 для каждой записи, представляющей прогнозируемую вероятность «Истина», и каждая метка представляет собой точно 0 или 1, представляющие наземную истину «Ложь», и "True" соответственно), то мы можем добавить показатель Центра клиентов следующим образом:

# if y_pred > threshold we predict true. 
# Sometimes we set this to something different to 0.5 if we have unbalanced categories

threshold = 0.5  

def mcc_metric(y_true, y_pred):
  predicted = tf.cast(tf.greater(y_pred, threshold), tf.float32)
  true_pos = tf.math.count_nonzero(predicted * y_true)
  true_neg = tf.math.count_nonzero((predicted - 1) * (y_true - 1))
  false_pos = tf.math.count_nonzero(predicted * (y_true - 1))
  false_neg = tf.math.count_nonzero((predicted - 1) * y_true)
  x = tf.cast((true_pos + false_pos) * (true_pos + false_neg) 
      * (true_neg + false_pos) * (true_neg + false_neg), tf.float32)
  return tf.cast((true_pos * true_neg) - (false_pos * false_neg), tf.float32) / tf.sqrt(x)

который мы можем включить в наш вызов model.compile:

model.compile(optimizer='adam',
              loss=tf.keras.losses.binary_crossentropy,
              metrics=['accuracy', mcc_metric])

Пример

Вот полный рабочий пример, в котором мы классифицируем многозначные цифры в зависимости от того, больше ли они 4:

mnist = tf.keras.datasets.mnist

(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0
y_train, y_test = 0 + (y_train > 4), 0 + (y_test > 4)

def mcc_metric(y_true, y_pred):
  predicted = tf.cast(tf.greater(y_pred, 0.5), tf.float32)
  true_pos = tf.math.count_nonzero(predicted * y_true)
  true_neg = tf.math.count_nonzero((predicted - 1) * (y_true - 1))
  false_pos = tf.math.count_nonzero(predicted * (y_true - 1))
  false_neg = tf.math.count_nonzero((predicted - 1) * y_true)
  x = tf.cast((true_pos + false_pos) * (true_pos + false_neg) 
      * (true_neg + false_pos) * (true_neg + false_neg), tf.float32)
  return tf.cast((true_pos * true_neg) - (false_pos * false_neg), tf.float32) / tf.sqrt(x)

model = tf.keras.models.Sequential([
  tf.keras.layers.Flatten(input_shape=(28, 28)),
  tf.keras.layers.Dense(128, activation='relu'),
  tf.keras.layers.Dropout(0.2),
  tf.keras.layers.Dense(10, activation='relu'),
  tf.keras.layers.Dense(1, activation='sigmoid')
])

model.compile(optimizer='adam',
              loss=tf.keras.losses.binary_crossentropy,
              metrics=['accuracy', mcc_metric])

model.fit(x_train, y_train, epochs=5)
model.evaluate(x_test, y_test)

выход:

Epoch 1/5
60000/60000 [==============================] - 7s 113us/sample - loss: 0.1391 - acc: 0.9483 - mcc_metric: 0.8972
Epoch 2/5
60000/60000 [==============================] - 6s 96us/sample - loss: 0.0722 - acc: 0.9747 - mcc_metric: 0.9495
Epoch 3/5
60000/60000 [==============================] - 6s 97us/sample - loss: 0.0576 - acc: 0.9797 - mcc_metric: 0.9594
Epoch 4/5
60000/60000 [==============================] - 6s 96us/sample - loss: 0.0479 - acc: 0.9837 - mcc_metric: 0.9674
Epoch 5/5
60000/60000 [==============================] - 6s 95us/sample - loss: 0.0423 - acc: 0.9852 - mcc_metric: 0.9704
10000/10000 [==============================] - 1s 58us/sample - loss: 0.0582 - acc: 0.9818 - mcc_metric: 0.9639
[0.05817381642502733, 0.9818, 0.9638971]
person Stewart_R    schedule 03.07.2019

Поскольку спрашивающий принял версию Python от sklearn, вот ответ Stewart_R на чистом Python:

from math import sqrt
def mcc(tp, fp, tn, fn):

    # https://stackoverflow.com/a/56875660/992687
    x = (tp + fp) * (tp + fn) * (tn + fp) * (tn + fn)
    return ((tp * tn) - (fp * fn)) / sqrt(x)

Его преимущество заключается в том, что он является общим, а не только для оценки бинарных классификаций.

person The Unfun Cat    schedule 14.11.2019

Другие ответы на вопрос (например, реализация MCC Keras/Tensorflow) ограничены в том смысле, что для этого требуется двоичная классификация и один выходной столбец. Если бы ваша настройка была не такой, функция дала бы вам неправильное значение MCC без какой-либо ошибки.

Конечно, MCC можно вычислить для вывода с несколькими классами и несколькими столбцами. Общая пользовательская метрическая функция для Keras (Tensorflow) MCC выглядит следующим образом.

import tensorflow as tf
from keras import backend as K

def keras_calculate_mcc_from_conf(confusion_m):
    """tensor version of MCC calculation from confusion matrix"""
    # as in Gorodkin (2004)
    N = K.sum(confusion_m)
    up = N * tf.linalg.trace(confusion_m) - K.sum(tf.matmul(confusion_m, confusion_m))
    down_left = K.sqrt(N ** 2 - K.sum(tf.matmul(confusion_m, K.transpose(confusion_m))))
    down_right = K.sqrt(N ** 2 - K.sum(tf.matmul(K.transpose(confusion_m), confusion_m)))
    mcc_val = up / (down_left * down_right + K.epsilon())
    return mcc_val


def keras_better_to_categorical(y_pred_in):
    """tensor version of to_categorical"""
    nclass = K.shape(y_pred_in)[1]
    y_pred_argmax = K.argmax(y_pred_in, axis=1)
    y_pred = tf.one_hot(tf.cast(y_pred_argmax, tf.int32), depth=nclass)
    y_pred = tf.cast(y_pred, tf.float32)
    return y_pred


def mcc(y_true, y_pred):
    """To calculate Matthew's correlation coefficient for multi-class classification"""
    # this is necessary to make y_pred values of 0 or 1 because
    # y_pred may contain other value (e.g., 0.6890)
    y_pred = keras_better_to_categorical(y_pred)

    # now it's straightforward to calculate confusion matrix and MCC
    confusion_m = tf.matmul(K.transpose(y_true), y_pred)
    return keras_calculate_mcc_from_conf(confusion_m)


# test mcc
actuals = tf.constant([[1.0, 0], [1.0, 0], [0, 1.0], [1.0, 0]], dtype=tf.float32)
preds = tf.constant([[1.0, 0], [0, 1.0], [0, 1.0], [1.0, 0]], dtype=tf.float32)
mcc_val = mcc(actuals, preds)
print(K.eval(mcc_val))

Также обратите внимание, что значения MCC, напечатанные из Keras во время итераций, будут неверными из-за расчета метрики на размер пакета. Вы можете доверять значению MCC только после вызова оценки или оценки после подбора. Это связано с тем, что MCC для всей выборки не является суммой/средним значением частей, в отличие от других показателей. Например, если размер пакета равен единице, напечатанный MCC будет равен нулю во время итераций.

person Tae-Sung Shin    schedule 24.10.2020