【问题标题】:How do I calculate the matthews correlation coefficient in tensorflow如何计算张量流中的马修斯相关系数
【发布时间】:2019-11-13 20:41:02
【问题描述】:

所以我用 tensorflow keras 做了一个模型,它似乎工作正常。但是,我的主管说计算 Matthews 相关系数以及它已经计算的准确度和损失会很有用。

我的模型与教程 (https://www.tensorflow.org/tutorials/keras/basic_classification) 中的代码非常相似,只是数据集要小得多。

是否有预构建的函数,或者我是否必须获得每个测试的预测并手动计算?

【问题讨论】:

    标签: python-2.7 tensorflow machine-learning tf.keras


    【解决方案1】:

    没有什么是开箱即用的,但我们可以根据自定义指标中的公式计算它。

    您提供的基本分类链接用于多类分类问题,而 Matthews 相关系数专门用于二元分类问题。

    假设您的模型以“正常”方式构建此类问题(即,y_pred 是一个介于 0 和 1 之间的数字,表示每条记录的预测概率为“真”,并且每个标签都恰好是 01 分别代表基本事实“假”和“真”)然后我们可以添加一个 MCC 指标如下:

    # 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 数字进行分类:

    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]
    

    【讨论】:

      【解决方案2】:

      计算马修斯相关系数的预建函数

      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) 
      

      请参阅documentation

      【讨论】:

      【解决方案3】:

      由于提问者接受了来自 sklearn 的 Python 版本,因此这里是纯 Python 中的 Stewart_Rs 答案:

      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)
      

      它具有通用性的优点,而不仅仅是用于评​​估二元分类。

      【讨论】:

        【解决方案4】:

        该问题的其他答案(即 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))
        

        另外请注意,由于每个批次大小的度量计算,迭代期间从 Keras 打印的 MCC 值将不正确。您只能在拟合后调用“评估”或“评分”来信任 MCC 值。这是因为与其他指标不同,整个样本的 MCC 不是部分的总和/平均值。例如,如果您的批量大小为 1,则在迭代期间打印的 MCC 将为零。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-04-02
          • 2019-07-04
          • 2017-01-19
          • 1970-01-01
          • 2014-04-16
          • 2017-06-12
          相关资源
          最近更新 更多