Имеет ли смысл эта кривая ROC? - PullRequest
0 голосов
/ 01 марта 2019

Этот код возвращает и отображает истинную положительную скорость, ложную положительную скорость, истинное положительное число, ложное положительное число, основанное на прогнозных и истинных значениях:

def get_all_stats(y_true , y_pred) : 

    def perf_measure(y_true, y_pred):

        TP = 0
        FP = 0
        TN = 0
        FN = 0

        for i in range(len(y_true)): 
            if y_true[i] == 1 and y_pred[i] == 1:
                TP += 1
            if y_pred[i]==1 and y_true[i]!=y_pred[i]:
                FP += 1
            if y_true[i]== 0 and y_pred[i]==0:
                TN += 1
            if y_pred[i]==0 and y_true[i] != y_pred[i]:
                FN += 1

        if(FP == 0) : 
            FPR = 0;
        else : 
            FPR = FP / (FP + TN)

        if(TP == 0) : 
            TPR = 0
        else : 
            TPR = TP / (TP + FN)

        return(TN , FPR, FN , TPR , TP , FP)

    tn, fpr, fn, tpr, tp , fp = perf_measure(y_true, y_pred)

    return tpr , fpr , tp , fp

tpr1 , fpr1 , tp1 , fp1 = get_all_stats(y_true=[1,1,1] , y_pred=[1,0,0])
tpr2 , fpr2 , tp2 , fp2 = get_all_stats(y_true=[1,0,1] , y_pred=[0,1,0])
tpr3 , fpr3 , tp3 , fp3 = get_all_stats(y_true=[0,0,0] , y_pred=[1,0,0])

plt.figure(figsize=(12,6))
plt.tick_params(labelsize=12)

print(tpr1 , fpr1 , tp1 , fp1)
print(tpr2 , fpr2 , tp2 , fp2)
print(tpr3 , fpr3 , tp3 , fp3)

plt.plot([fpr1,fpr2,fpr3], [tpr1 , tpr2, tpr3], color='blue', label='')
plt.ylabel("TPR",fontsize=16)
plt.xlabel("FPR",fontsize=16)
plt.legend()

Полученный результирующий график ROC:

enter image description here

Чтобы имитировать три разных ложноположительных и истинно положительных показателя и разные пороговые значения, рассчитайте эти значения, реализовав функцию get_all_stats три раза с разными

tpr1 , fpr1 , tp1 , fp1 = get_all_stats(y_true=[1,1,1] , y_pred=[1,0,0])
tpr2 , fpr2 , tp2 , fp2 = get_all_stats(y_true=[1,0,1] , y_pred=[0,1,0])
tpr3 , fpr3 , tp3 , fp3 = get_all_stats(y_true=[0,0,0] , y_pred=[1,0,0])

Существует 9 случаев, которые должны быть классифицированы как 1 или 0, где значения истинности: [1,1,1,1,0,1,0,0,0]

На пороге 1 прогнозируемые значения [1,0,0], где значения истинности на этом пороге[1,1,1].

На пороге 2 прогнозируемые значения [0,1,0], где значения истинности на этом пороге [1,0,1].

На пороге 3 прогнозируемые значения [1,0,0], где значения истинностипри этом пороге [0,0,0].

Как видно, сгенерированный график полученного классификатора отличается от «типичных» кривых ROC:

enter image description here

При первом снижении, а затем снижаются ложноположительные и истинно положительные показатели, в результате чего линия «возвращается».Правильно ли я реализовал кривую ROC?Можно ли рассчитать AUC для этой кривой?

1 Ответ

0 голосов
/ 01 марта 2019

Хорошо, мотивирован, чтобы помочь, потому что у вас много повторений -> помогло многим другим.Здесь мы идем.

Эта кривая ROC не имеет смысла.Проблема в том, что вы рассчитываете FPR / TPR только для подмножеств ваших данных с разными пороговыми значениями.На каждом пороге вы должны использовать все данных для расчета FPR и TPR.Таким образом, у вас, кажется, есть 3 точки на вашем графике, но вы должны были иметь только одну точку с FPR / TPR для y_true = [1,1,1,1,0,1,0,0,0] и y_pred = [1,0,0,0,1,0,1,0,0].Однако, чтобы гарантировать, что у вас есть фактическая кривая ROC, вы также не можете просто составить значения y_pred при различных пороговых значениях - они должны быть получены из фактических прогнозируемых вероятностей, которые затем будут соответствующим образом пороговыми.Я немного изменил ваш код, потому что мне нравится использовать numpy;вот как можно рассчитать ROC-кривую.

# start with the true labels, as you did
y_true = np.array([1, 1, 1, 1, 0, 1, 0, 0, 0])
# and a predicted probability of each being a "1"
# I just used random numbers for these, but you would get them
# from your classifier
predictions = np.array([
    0.07485627, 0.72546085, 0.60287482,
    0.90537829, 0.75789236, 0.01852192,
    0.85425979, 0.36881312, 0.63893516
])

# now define a set of thresholds (the more thresholds, the better
# the curve will look). There's a smarter way to do this in practice
# (you can sort the predicted probabilities and just have one threshold
# between each), but this is just to help with understanding
thresholds = np.linspace(0, 1, 11) # 0.1, 0.2, ..., 1.0

fprs = []
tprs = []

# we can precompute which inputs are actually 1s/0s and how many of each
true_1_idx = np.where(y_true == 1)[0]
true_0_idx = np.where(y_true == 0)[0]
n_true_1 = len(true_1_idx)
n_true_0 = len(true_0_idx)

for threshold in thresholds:
    # now, for each threshold, we use that on the underlying probabilities
    # to get the actual predicted classes
    pred_classes = predictions >= threshold
    # and compute FPR/TPR from those
    tprs.append((pred_classes[true_1_idx] == 1).sum() / n_true_1)
    fprs.append((pred_classes[true_0_idx] == 1).sum() / n_true_0)

plt.figure(figsize=(12,6))
plt.tick_params(labelsize=12)

plt.plot(fprs, tprs, color='blue')
plt.ylabel("TPR",fontsize=16)
plt.xlabel("FPR",fontsize=16)

enter image description here

Обратите внимание, что кривая ROC всегда неубывающая в TPR (ось Y)по мере увеличения FPR (ось X);то есть, он повышается, когда вы двигаетесь вправо.Это ясно из того, как работает порог.При пороге 0 все прогнозы равны «1», поэтому мы имеем FPR = TPR = 1. Увеличение порога дает меньше прогнозов «1», поэтому FPR и TPR могут оставаться только одинаковыми или уменьшаться.

Обратите внимание, что, даже если мы использовали оптимальные пороги, на кривой все еще есть скачки, потому что у нас есть конечное количество данных, поэтому конечное число различных пар TPR / FPR мы можем получить с любым порогом.Если у вас достаточно данных, то все начинает выглядеть гладко.Здесь я заменил несколько строк в приведенном выше коде, чтобы получить более плавный график:

n_points = 1000
y_true = np.random.randint(0, 2, size=n_points)
predictions = np.random.random(n_points)

thresholds = np.linspace(0, 1, 1000)

enter image description here

Если неясно, AUC0.5 - наихудший из возможных, и вы можете видеть, что это то, что мы получаем со случайными «предсказаниями».Если ваш AUC хуже 0,5, вы можете перевернуть каждое предсказание лучше 0,5 (и, возможно, что-то не так с вашей моделью / тренировкой).

Если вы на самом деле хотите построить кривую ROC на практике, непросто напишите это, чтобы узнать немного больше, используйте sklearn's roc_curve.У них также есть roc_auc_score, чтобы получить AUC для вас.

...