代码之家  ›  专栏  ›  技术社区  ›  Luis Ramon Ramirez Rodriguez

灵敏度-特异性图python

  •  -1
  • Luis Ramon Ramirez Rodriguez  · 技术社区  · 7 年前

    我试图复制一个类似于此的敏感性-特异性图: 其中X轴是阈值

    enter image description here

    但我还没有找到如何做到这一点,一些斯卡利恩指标,如ROC曲线,会返回真阳性和假阳性,但我没有找到任何选项来绘制此图。

    我试图将prob与实际标签进行比较以保持计数,我得到的曲线如下:

    enter image description here

    因此,X标签必须具有一定的规格化程度,以便曲线可以实际上下移动。

    0 回复  |  直到 7 年前
        1
  •  6
  •   ApproachingDarknessFish    7 年前

    我不认为那个情节显示了你认为它显示的东西。随着阈值降至零,灵敏度将接近1,因为100%的观察结果将被归类为阳性,而假阴性率将降至零。同样,随着阈值接近1,选择性将接近1,因为每次观察都将被归类为阴性,而假阳性率将为零。所以这个曲线图没有显示出灵敏度或选择性。

    为了将选择性和灵敏度绘制在x轴上作为阈值的函数,我们可以使用内置ROC功能并从中提取值,以我们自己的方式绘制它们。给定二进制标签向量 test_y ,关联预测值矩阵 test_x ,和一个合适的 RandomForestClassifier 对象 rfc :

    import matplotlib.pyplot as plt
    import numpy as np
    from sklearn.metrics import precision_score, recall_score
    
    # Get the estimated probabilities of each observation being categorized as positive
    # [:,1] for probabilities of negative
    predicted_y_probs = rfc.predict_proba(test_x)[:,0]
    
    thresholds = np.linspace(0,1,20) # or however many points you want
    
    sensitivities = [recall_score(test_y, predicted_y_probs >= t) for t in thresholds]
    selectivities = [precision_score(test_y, predicted_y_probs >= t) for t in thresholds]
    plt.plot(thresholds, sensitivies, label='sensitivity')
    plt.plot(thresholds, selectivities, label='selectivity')
    plt.legend()
    

    然而,这将 不 重新创建您作为参考提供的图,该图似乎显示了每个被归类为正的观察的估计概率的分布。换句话说,该图中的阈值是一个常数,x轴向我们显示了每个预测相对于该(固定)阈值下降的位置。它不能直接告诉我们灵敏度或选择性。如果你真的想要这样的情节,请继续阅读。

    我想不出重建这些平滑曲线的方法,因为密度图将延伸到零以下和1以上,但我们可以使用直方图显示信息。使用与之前相同的变量:

    # Specify range to ensure both groups show up the same width.
    bins = np.linspace(0,1,10)
    
    # Show distributions of estimated probabilities for the two classes.
    plt.hist(predicted_y_probs[test_y == 1], alpha=0.5, color='red', label='positive', bins=bins)
    plt.hist(predicted_y_probs[test_y == 0], alpha=0.5, color='green', label='negative', bins=bins)
    
    # Show the threshold.
    plt.axvline(0.5, c='black', ls='dashed')
    
    # Add labels
    plt.legend()
    

    我只使用三个物种中的两个物种运行了经典Iris数据集的这段代码,并得到了以下输出。Versicolor为“阳性”,viriginica为“阴性”,setosa被忽略以生成二元分类。请注意,我的模型具有完美的回忆能力,因此所有versicolor的概率都非常接近1.0。因为只有100个样本,其中大多数都被正确分类,所以这是一个相当大的障碍,但希望它能让人理解这个想法。

    histogram with green columns distributed near 0.0, 0.4, and 0.9, and one red column at 1.0

        2
  •  4
  •   Him    7 年前

    建立在 @ApproachingDarknessFish's answer ,可以将各种分布拟合到生成的直方图中,但并非所有分布都在[0,1]之外。例如,beta分布可以很好地捕获[0,1]上的大多数单峰分布,至少为了可视化:

    import numpy as np
    import matplotlib.pyplot as plt
    import scipy.stats
    
    test_y = np.array([0]*100 + [1]*100)
    predicted_y_probs = np.concatenate((np.random.beta(2,5,100), np.random.beta(8,3,100)))
    
    def estimate_beta(X):
        xbar = np.mean(X)
        vbar = np.var(X,ddof=1)
        alphahat = xbar*(xbar*(1-xbar)/vbar - 1)
        betahat = (1-xbar)*(xbar*(1-xbar)/vbar - 1)
        return alphahat, betahat
    
    positive_beta_estimates = estimate_beta(predicted_y_probs[test_y == 1])
    negative_beta_estimates = estimate_beta(predicted_y_probs[test_y == 0])
    
    unit_interval = np.linspace(0,1,100)
    plt.plot(unit_interval, scipy.stats.beta.pdf(unit_interval, *positive_beta_estimates), c='r', label="positive")
    plt.plot(unit_interval, scipy.stats.beta.pdf(unit_interval, *negative_beta_estimates), c='g', label="negative")
    
    # Show the threshold.
    plt.axvline(0.5, c='black', ls='dashed')
    plt.xlim(0,1)
    
    # Add labels
    plt.legend()
    

    fitted beta distribution

    推荐文章