2016-10-03 3 views
5

Я нарисовал кривую прецизионного отзыва, используя sklearnprecision_recall_curve функция и matplotlib упаковка. Для тех из вас, кто знаком с кривой прецизионного отзыва, вы знаете, что некоторые научные сообщества принимают его только при его интерполяции, подобно этому примеру here. Теперь мой вопрос в том, что кто-нибудь из вас знает, как сделать интерполяцию в python? Я искал решение какое-то время, но без успеха! Любая помощь будет принята с благодарностью.Как нарисовать кривую прецизионного отзыва с интерполяцией в 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])) 

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

ответ

1

Итерация назад может быть выполнена для удаления увеличивающих частей в precision. Затем вертикальные и горизонтальные линии могут быть нанесены на график, как указано в ответе Беннетта Брауна на vertical & horizontal lines in 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() 

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

enter image description here

+0

Спасибо за ответ. Я также написал решение, адаптированное к выходу precision_recall_curve в sklearn. – user823743

2

@ решение Френсис может быть векторным с помощью 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') 

enter image description here

+0

Ваше решение помогло мне адаптировать код @ francis к выходу функции precision_recall_curve. Я написал решение. +1, спасибо. – user823743