如何从多类分类的混淆矩阵中提取 False Positive、False Negative
How to extract False Positive, False Negative from a confusion matrix of multiclass classification
我正在使用以下 Keras 代码对 mnist 数据进行分类。从 sklearn.metrics
的 confusion_matrix
命令我得到了混淆矩阵,从 TruePositive= sum(numpy.diag(cm1))
命令我能够得到真阳性。但我很困惑如何获得真阴性、假阳性、假阴性。我阅读了 here 的解决方案,但用户评论让我感到困惑。请帮助编码以获取参数。
from sklearn.metrics import confusion_matrix
import keras
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D
from keras import backend as K
import numpy as np
(x_train, y_train), (x_test, y_test) = mnist.load_data()
batch_size = 128
num_classes = 10
epochs = 1
img_rows, img_cols = 28, 28
y_test1=y_test
if K.image_data_format() == 'channels_first':
x_train = x_train.reshape(x_train.shape[0], 1, img_rows, img_cols)
x_test = x_test.reshape(x_test.shape[0], 1, img_rows, img_cols)
input_shape = (1, img_rows, img_cols)
else:
x_train = x_train.reshape(x_train.shape[0], img_rows, img_cols, 1)
x_test = x_test.reshape(x_test.shape[0], img_rows, img_cols, 1)
input_shape = (img_rows, img_cols, 1)
x_train = x_train.astype('float32')
x_test = x_test.astype('float32')
x_train /= 255
x_test /= 255
y_train = keras.utils.to_categorical(y_train, num_classes)
y_test = keras.utils.to_categorical(y_test, num_classes)
model = Sequential()
model.add(Conv2D(32, kernel_size=(3, 3),
activation='relu',
input_shape=input_shape))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Flatten())
#model.add(GlobalAveragePooling2D())
#model.add(GlobalMaxPooling2D())
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(num_classes, activation='softmax'))
model.compile(loss=keras.losses.binary_crossentropy,
optimizer=keras.optimizers.Adadelta(),
metrics=['accuracy'])
model.fit(x_train, y_train,
batch_size=batch_size,
epochs=epochs,
verbose=1,
validation_data=(x_test, y_test))
pre_cls=model.predict_classes(x_test)
cm1 = confusion_matrix(y_test1,pre_cls)
print('Confusion Matrix : \n', cm1)
TruePositive= sum(np.diag(cm1))
首先,你的代码有遗漏-为了运行,我需要添加以下命令:
import keras
(x_train, y_train), (x_test, y_test) = mnist.load_data()
完成后,给出混淆矩阵 cm1
:
array([[ 965, 0, 1, 0, 0, 2, 6, 1, 5, 0],
[ 0, 1113, 4, 2, 0, 0, 3, 0, 13, 0],
[ 8, 0, 963, 14, 5, 1, 7, 8, 21, 5],
[ 0, 0, 3, 978, 0, 7, 0, 6, 12, 4],
[ 1, 0, 4, 0, 922, 0, 9, 3, 3, 40],
[ 4, 1, 1, 27, 0, 824, 6, 1, 20, 8],
[ 11, 3, 1, 1, 5, 6, 925, 0, 6, 0],
[ 2, 6, 17, 8, 2, 0, 1, 961, 2, 29],
[ 5, 1, 2, 13, 4, 6, 2, 6, 929, 6],
[ 6, 5, 0, 7, 5, 6, 1, 6, 10, 963]])
这里是如何获得请求的 TP、FP、FN、TN per class:
真阳性就是对角线元素:
TruePositive = np.diag(cm1)
TruePositive
# array([ 965, 1113, 963, 978, 922, 824, 925, 961, 929, 963])
误报是各列的总和减去对角线元素:
FalsePositive = []
for i in range(num_classes):
FalsePositive.append(sum(cm1[:,i]) - cm1[i,i])
FalsePositive
# [37, 16, 33, 72, 21, 28, 35, 31, 92, 92]
同样,假阴性是相应行的总和,减去对角线元素:
FalseNegative = []
for i in range(num_classes):
FalseNegative.append(sum(cm1[i,:]) - cm1[i,i])
FalseNegative
# [15, 22, 69, 32, 60, 68, 33, 67, 45, 46]
现在,True Negatives 有点棘手;让我们首先想一想真正的否定到底意味着什么,相对于 class 0
:它意味着所有被正确识别为 而不是 0
[ 的样本=42=]。所以,本质上我们应该做的是从混淆矩阵中删除相应的行和列,然后将所有剩余元素相加:
TrueNegative = []
for i in range(num_classes):
temp = np.delete(cm1, i, 0) # delete ith row
temp = np.delete(temp, i, 1) # delete ith column
TrueNegative.append(sum(sum(temp)))
TrueNegative
# [8998, 8871, 9004, 8950, 9057, 9148, 9040, 9008, 8979, 8945]
让我们做一个完整性检查:对于每个class,TP、FP、FN和TN的总和必须等于我们测试集的大小(此处为 10,000):让我们确认确实如此:
l = len(y_test)
for i in range(num_classes):
print(TruePositive[i] + FalsePositive[i] + FalseNegative[i] + TrueNegative[i] == l)
结果是
True
True
True
True
True
True
True
True
True
True
我正在使用以下 Keras 代码对 mnist 数据进行分类。从 sklearn.metrics
的 confusion_matrix
命令我得到了混淆矩阵,从 TruePositive= sum(numpy.diag(cm1))
命令我能够得到真阳性。但我很困惑如何获得真阴性、假阳性、假阴性。我阅读了 here 的解决方案,但用户评论让我感到困惑。请帮助编码以获取参数。
from sklearn.metrics import confusion_matrix
import keras
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D
from keras import backend as K
import numpy as np
(x_train, y_train), (x_test, y_test) = mnist.load_data()
batch_size = 128
num_classes = 10
epochs = 1
img_rows, img_cols = 28, 28
y_test1=y_test
if K.image_data_format() == 'channels_first':
x_train = x_train.reshape(x_train.shape[0], 1, img_rows, img_cols)
x_test = x_test.reshape(x_test.shape[0], 1, img_rows, img_cols)
input_shape = (1, img_rows, img_cols)
else:
x_train = x_train.reshape(x_train.shape[0], img_rows, img_cols, 1)
x_test = x_test.reshape(x_test.shape[0], img_rows, img_cols, 1)
input_shape = (img_rows, img_cols, 1)
x_train = x_train.astype('float32')
x_test = x_test.astype('float32')
x_train /= 255
x_test /= 255
y_train = keras.utils.to_categorical(y_train, num_classes)
y_test = keras.utils.to_categorical(y_test, num_classes)
model = Sequential()
model.add(Conv2D(32, kernel_size=(3, 3),
activation='relu',
input_shape=input_shape))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Flatten())
#model.add(GlobalAveragePooling2D())
#model.add(GlobalMaxPooling2D())
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(num_classes, activation='softmax'))
model.compile(loss=keras.losses.binary_crossentropy,
optimizer=keras.optimizers.Adadelta(),
metrics=['accuracy'])
model.fit(x_train, y_train,
batch_size=batch_size,
epochs=epochs,
verbose=1,
validation_data=(x_test, y_test))
pre_cls=model.predict_classes(x_test)
cm1 = confusion_matrix(y_test1,pre_cls)
print('Confusion Matrix : \n', cm1)
TruePositive= sum(np.diag(cm1))
首先,你的代码有遗漏-为了运行,我需要添加以下命令:
import keras
(x_train, y_train), (x_test, y_test) = mnist.load_data()
完成后,给出混淆矩阵 cm1
:
array([[ 965, 0, 1, 0, 0, 2, 6, 1, 5, 0],
[ 0, 1113, 4, 2, 0, 0, 3, 0, 13, 0],
[ 8, 0, 963, 14, 5, 1, 7, 8, 21, 5],
[ 0, 0, 3, 978, 0, 7, 0, 6, 12, 4],
[ 1, 0, 4, 0, 922, 0, 9, 3, 3, 40],
[ 4, 1, 1, 27, 0, 824, 6, 1, 20, 8],
[ 11, 3, 1, 1, 5, 6, 925, 0, 6, 0],
[ 2, 6, 17, 8, 2, 0, 1, 961, 2, 29],
[ 5, 1, 2, 13, 4, 6, 2, 6, 929, 6],
[ 6, 5, 0, 7, 5, 6, 1, 6, 10, 963]])
这里是如何获得请求的 TP、FP、FN、TN per class:
真阳性就是对角线元素:
TruePositive = np.diag(cm1)
TruePositive
# array([ 965, 1113, 963, 978, 922, 824, 925, 961, 929, 963])
误报是各列的总和减去对角线元素:
FalsePositive = []
for i in range(num_classes):
FalsePositive.append(sum(cm1[:,i]) - cm1[i,i])
FalsePositive
# [37, 16, 33, 72, 21, 28, 35, 31, 92, 92]
同样,假阴性是相应行的总和,减去对角线元素:
FalseNegative = []
for i in range(num_classes):
FalseNegative.append(sum(cm1[i,:]) - cm1[i,i])
FalseNegative
# [15, 22, 69, 32, 60, 68, 33, 67, 45, 46]
现在,True Negatives 有点棘手;让我们首先想一想真正的否定到底意味着什么,相对于 class 0
:它意味着所有被正确识别为 而不是 0
[ 的样本=42=]。所以,本质上我们应该做的是从混淆矩阵中删除相应的行和列,然后将所有剩余元素相加:
TrueNegative = []
for i in range(num_classes):
temp = np.delete(cm1, i, 0) # delete ith row
temp = np.delete(temp, i, 1) # delete ith column
TrueNegative.append(sum(sum(temp)))
TrueNegative
# [8998, 8871, 9004, 8950, 9057, 9148, 9040, 9008, 8979, 8945]
让我们做一个完整性检查:对于每个class,TP、FP、FN和TN的总和必须等于我们测试集的大小(此处为 10,000):让我们确认确实如此:
l = len(y_test)
for i in range(num_classes):
print(TruePositive[i] + FalsePositive[i] + FalseNegative[i] + TrueNegative[i] == l)
结果是
True
True
True
True
True
True
True
True
True
True