Как нарисовать кривую точности-отзыва с интерполяцией в Python?

Я нарисовал кривую точности-отзыва, используя sklearn precision_recall_curvefunction и matplotlib package. Те из вас, кто знаком с кривой точности-отзыва, знают, что некоторые научные сообщества принимают ее только тогда, когда она интерполируется, как в этом примере здесь. Теперь мой вопрос: знает ли кто-нибудь из вас, как выполнять интерполяцию в Python? Некоторое время я искал решение, но безуспешно! Любая помощь будет принята с благодарностью.

Решение. Оба решения от @francis и @ali_m верны и вместе решили мою проблему. Итак, предполагая, что вы получаете результат от функции precision_recall_curve в sklearn, вот что я сделал для построения графика:

precision["micro"], recall["micro"], _ = precision_recall_curve(y_test.ravel(),scores.ravel())
pr = copy.deepcopy(precision[0])
rec = copy.deepcopy(recall[0])
prInv = np.fliplr([pr])[0]
recInv = np.fliplr([rec])[0]
j = rec.shape[0]-2
while j>=0:
    if prInv[j+1]>prInv[j]:
        prInv[j]=prInv[j+1]
    j=j-1
decreasing_max_precision = np.maximum.accumulate(prInv[::-1])[::-1]
plt.plot(recInv, decreasing_max_precision, marker= markers[mcounter], label=methodNames[countOfMethods]+': AUC={0:0.2f}'.format(average_precision[0]))

И эти строки построят интерполированные кривые, если вы поместите их в цикл for и передадите ему данные каждого метода на каждой итерации. Обратите внимание, что при этом не будут построены неинтерполированные кривые прецизионного возврата.


person user823743    schedule 03.10.2016    source источник
comment
Пожалуйста, не предлагайте решение вопроса. Напишите на это ответ, если считаете, что этой информацией следует поделиться.   -  person Cindy Meister    schedule 26.03.2020


Ответы (2)


Для удаления возрастающих частей в precision может быть выполнена итерация в обратном направлении. Затем можно построить вертикальные и горизонтальные линии, как указано в ответе Беннета Брауна на вертикальные и горизонтальные линии в matplotlib.

Вот пример кода:

import numpy as np
import matplotlib.pyplot as plt

#just a dummy sample
recall=np.linspace(0.0,1.0,num=42)
precision=np.random.rand(42)*(1.-recall)
precision2=precision.copy()
i=recall.shape[0]-2

# interpolation...
while i>=0:
    if precision[i+1]>precision[i]:
        precision[i]=precision[i+1]
    i=i-1

# plotting...
fig, ax = plt.subplots()
for i in range(recall.shape[0]-1):
    ax.plot((recall[i],recall[i]),(precision[i],precision[i+1]),'k-',label='',color='red') #vertical
    ax.plot((recall[i],recall[i+1]),(precision[i+1],precision[i+1]),'k-',label='',color='red') #horizontal

ax.plot(recall,precision2,'k--',color='blue')
#ax.legend()
ax.set_xlabel("recall")
ax.set_ylabel("precision")
plt.savefig('fig.jpg')
fig.show()

И вот результат:

введите описание изображения здесь

person francis    schedule 03.10.2016
comment
Спасибо за ответ. Я также написал решение, адаптированное к выводу precision_recall_curve в sklearn. - person user823743; 07.10.2016

Решение @ francis можно векторизовать с помощью np.maximum.accumulate.

import numpy as np
import matplotlib.pyplot as plt

recall = np.linspace(0.0, 1.0, num=42)
precision = np.random.rand(42)*(1.-recall)

# take a running maximum over the reversed vector of precision values, reverse the
# result to match the order of the recall vector
decreasing_max_precision = np.maximum.accumulate(precision[::-1])[::-1]

Вы также можете использовать plt.step, чтобы избавиться от цикла for, используемого для построения графика. :

fig, ax = plt.subplots(1, 1)
ax.hold(True)
ax.plot(recall, precision, '--b')
ax.step(recall, decreasing_max_precision, '-r')

введите описание изображения здесь

person ali_m    schedule 04.10.2016
comment
Ваше решение помогло мне адаптировать код @ francis к выходным данным функции precision_recall_curve. Я написал решение. +1, спасибо. - person user823743; 07.10.2016