How to draw a precision-recall curve with interpolation in python?
<p>I have drawn a precision-recall curve using <code>sklearn</code> <code>precision_recall_curve</code>function and <code>matplotlib</code> package. For those of you who are familiar with precision-recall curve you know that some scientific communities only accept it when its interpolated, similar to this example <a href="http://nlp.stanford.edu/IR-book/html/htmledition/evaluation-of-ranked-retrieval-results-1.html" rel="nofollow">here</a>. Now my question is if any of you know how to do the interpolation in python? I have been searching for a solution for a while now but with no success! Any help would be greatly appreciated. </p>

<p><strong>Solution:</strong> Both solutions by @francis and @ali_m are correct and together solved my problem. So, assuming that you get an output from the <code>precision_recall_curve</code> function in <code>sklearn</code>, here is what I did to plot the graph:</p>

<pre><code>        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&gt;=0:
            if prInv[j+1]&gt;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]))
</code></pre>

<p>And these lines will plot the interpolated curves if you put them in a for loop and pass it the data of each method at each iteration. Note that this will not plot the non-interpolated precision-recall curves.</p>

<p><strong>@francis's</strong> solution can be vectorized using <a href="http://docs.scipy.org/doc/numpy/reference/generated/numpy.ufunc.accumulate.html" rel="nofollow"><code>np.maximum.accumulate</code></a>.</p>

<pre><code>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]
</code></pre>

<p>You can also use <a href="http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.step" rel="nofollow"><code>plt.step</code></a> to get rid of the <code>for</code> loop used for plotting:</p>

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

<p><a href="http://i.stack.imgur.com/sCnKo.png" rel="nofollow"><img src="http://i.stack.imgur.com/sCnKo.png" alt="enter image description here"></a></p>

python numpy matplotlib scikit-learn precision-recall