Я использовал sklearn.metrics.jaccard_score
для сбора приведенной оценки из теста бинарной классификации моей модели Python. Он выводит, как показано ниже, но когда я вычисляю показатель вручную, он дает другое значение. Я ошибаюсь в значении «жаккарда» в использовании этой функции? Или я неправильно его использую? Все остальные показатели, собранные функциями sklearn, возвращают правильные значения.
Далее следует мой код с проверкой жаккарда вручную (выполнение в калькуляторе путем сравнения векторов как наборов дает то же самое, что и я (не так сильно) с облегчением).
def test(X, y, model):
predictions = model.predict(X, verbose=1).ravel()
report = classification_report(y, predictions, target_names=['nao_doentes', 'doentes'])
confMatrix = confusion_matrix(y, predictions)
tn, fp, fn, tp = confMatrix.ravel()
jaccard = jaccard_score(y, predictions) # Se comportando de forma estranha
print(tn, fp, fn, tp)
print(predictions)
print(y)
print(report)
print(confMatrix)
print("Jaccard by function: {}".format(jaccard))
# Note that in binary classification, recall of the positive class is also known as “sensitivity”;
# recall of the negative class is “specificity”.
dice = ((2*tp) / ((2*tp) + fp + fn))
jaccard = ((tp + tn) / ((2*(tp + tn + fn + fp)) - (tp + tn)))
print(dice)
print("Jaccard by hand: {}".format(jaccard))
И затем следует вывод:
2 0 1 1
[1. 0. 0. 0.]
[1 0 1 0]
precision recall f1-score support
nao_doentes 0.67 1.00 0.80 2
doentes 1.00 0.50 0.67 2
accuracy 0.75 4
macro avg 0.83 0.75 0.73 4
weighted avg 0.83 0.75 0.73 4
[[2 0]
[1 1]]
Jaccard by function: 0.5
0.6666666666666666
Jaccard by hand: 0.6
Во-вторых, почему classification_report
, кажется, ставит nao_doentes
(небольной, на португальском языке) как 1, а doentes
(больной) как 0? Разве это не должно быть наоборот? nao_doentes
устанавливается как 0, а doentes
как 1 в моих наборах (то есть в y).
Глядя на страницу справки , оценка Жаккара определяется как:
размер пересечения, разделенный на размер союза двух наборы этикеток,
И смотрят только на положительный класс:
jaccard_score может быть плохой метрикой, если нет положительных результатов для некоторых образцы или классы. Жаккара не определено, если нет истинных или предсказанные метки, и наша реализация вернет 0 баллов с предупреждение.
В матрице путаницы у вас есть:
intersection = tp # you have 1
union = tp+fp # you have 2
jaccard = intersection / union
и должно дать вам 1/(1+1) = 0,5.
Ваш ярлык правильный. Вы можете преобразовать метки, и вы увидите, что вы получаете ту же матрицу путаницы:
import pandas as pd
labels = pd.Categorical(['nao_doentes','doentes'],categories=['nao_doentes','doentes'])
prediction = [1 ,0 ,0, 0]
y = [1 ,0, 1, 0]
pd.crosstab(labels[y],labels[prediction])
col_0 nao_doentes doentes
row_0
nao_doentes 2 0
doentes 1 1
Оценка Jaccard, рассчитанная вручную в вашем вопросе, отличается от той, которая рассчитана с использованием scikit-learn по умолчанию jaccard_score
, потому что уравнение, которое вы использовали вручную, вычисляет микроусредненную оценку Jaccard, тогда как версия scikit-learn по умолчанию вычисляет оценка только для положительного класса ("Doentes").
Просто чтобы увидеть, как это происходит, мы можем посмотреть, как sklearn jaccard_score
с использованием метода по умолчанию сравнивается с расчетом вручную:
import numpy as np
from sklearn.metrics import jaccard_score
y_true = np.array([1, 0, 1, 0])
y_pred = np.array([1, 0, 0, 0])
tp = 1
tn = 2
fp = 0
fn = 1
jaccard_score(y_true, y_pred)
# 0.5
# And we can check this by using the definition of the Jaccard score for the positive class:
tp / (tp + fp + fn)
# 0.5
Теперь давайте посмотрим на микроусредненный балл Жаккара (определение «микроусредненного» здесь взято из документации scikit-learn:
# scikit-learn:
jaccard_score(y_true, y_pred, average='micro')
# 0.6
# Definition of micro-averaged ("Calculate metrics globally by counting
# the total true positives, false negatives and false positives").
# Here we have to define another set of outcomes but this time with the
# original negative class as the positive class:
tp_0 = 2
fp_0 = 1
tn_0 = 1
fn_0 = 0
(tp+tp_0)/(tp+tp_0+fp+fp_0+fn+fn_0)
# 0.6
# And let's now compare this to the original calculation by hand in the question:
(tp + tn) / ((2*(tp + tn + fn + fp)) - (tp + tn))
# 0.6