【问题标题】:Scikit-learn: How to obtain True Positive, True Negative, False Positive and False NegativeScikit-learn:如何获得真阳性、真阴性、假阳性和假阴性
【发布时间】:2015-09-28 05:25:20
【问题描述】:

我的问题:

我有一个大型 JSON 文件的数据集。我读取它并将其存储在trainList 变量中。

接下来,我对其进行预处理 - 以便能够使用它。

完成后我开始分类:

  1. 我使用kfold交叉验证方法来获得均值 准确度并训练分类器。
  2. 我做出预测并获得该折叠的准确性和混淆矩阵。
  3. 在此之后,我想获得True Positive(TP)True Negative(TN)False Positive(FP)False Negative(FN) 值。我将使用这些参数来获得 SensitivitySpecificity

最后,我会用它来放入 HTML 中,以便显示带有每个标签的 TP 的图表。

代码:

我目前拥有的变量:

trainList #It is a list with all the data of my dataset in JSON form
labelList #It is a list with all the labels of my data 

大部分方法:

#I transform the data from JSON form to a numerical one
X=vec.fit_transform(trainList)

#I scale the matrix (don't know why but without it, it makes an error)
X=preprocessing.scale(X.toarray())

#I generate a KFold in order to make cross validation
kf = KFold(len(X), n_folds=10, indices=True, shuffle=True, random_state=1)

#I start the cross validation
for train_indices, test_indices in kf:
    X_train=[X[ii] for ii in train_indices]
    X_test=[X[ii] for ii in test_indices]
    y_train=[listaLabels[ii] for ii in train_indices]
    y_test=[listaLabels[ii] for ii in test_indices]

    #I train the classifier
    trained=qda.fit(X_train,y_train)

    #I make the predictions
    predicted=qda.predict(X_test)

    #I obtain the accuracy of this fold
    ac=accuracy_score(predicted,y_test)

    #I obtain the confusion matrix
    cm=confusion_matrix(y_test, predicted)

    #I should calculate the TP,TN, FP and FN 
    #I don't know how to continue

【问题讨论】:

    标签: python machine-learning scikit-learn classification supervised-learning


    【解决方案1】:

    对于多类的情况,你需要的一切都可以从混淆矩阵中找到。例如,如果您的混淆矩阵如下所示:

    然后,您可以在每个班级中找到您要查找的内容,如下所示:

    使用 pandas/numpy,您可以像这样一次对所有类执行此操作:

    FP = confusion_matrix.sum(axis=0) - np.diag(confusion_matrix)  
    FN = confusion_matrix.sum(axis=1) - np.diag(confusion_matrix)
    TP = np.diag(confusion_matrix)
    TN = confusion_matrix.values.sum() - (FP + FN + TP)
    
    # Sensitivity, hit rate, recall, or true positive rate
    TPR = TP/(TP+FN)
    # Specificity or true negative rate
    TNR = TN/(TN+FP) 
    # Precision or positive predictive value
    PPV = TP/(TP+FP)
    # Negative predictive value
    NPV = TN/(TN+FN)
    # Fall out or false positive rate
    FPR = FP/(FP+TN)
    # False negative rate
    FNR = FN/(TP+FN)
    # False discovery rate
    FDR = FP/(TP+FP)
    
    # Overall accuracy
    ACC = (TP+TN)/(TP+FP+FN+TN)
    

    【讨论】:

    • 当我想计算 TN 的值时,我得到这个错误:'numpy.ndarray' object has no attribute 'values' 我正在使用 python 3。
    • 这假设您在此处使用 pandas DataFrame 实例作为混淆矩阵。如果您使用的是 numpy 数组,只需删除 .values 部分。
    • 很好的解释。是否有类似的方法可以分别为每个班级获取 TPR、TNR、PPV 等?
    • 很棒的答案@lucidv01d——我发现自己重复使用这段代码的次数足够多,以至于我写了一个package 来直接从pandas DataFrame 提供对这些指标的访问。您的答案、用户名和个人资料页面已正确归属:)
    • 这是一个超级答案。 @lucidc01d 你能分享一下你是怎么做这个可视化的吗?
    【解决方案2】:

    如果您有两个包含预测值和实际值的列表;正如您所做的那样,您可以将它们传递给一个函数,该函数将计算 TP、FP、TN、FN,如下所示:

    def perf_measure(y_actual, y_hat):
        TP = 0
        FP = 0
        TN = 0
        FN = 0
    
        for i in range(len(y_hat)): 
            if y_actual[i]==y_hat[i]==1:
               TP += 1
            if y_hat[i]==1 and y_actual[i]!=y_hat[i]:
               FP += 1
            if y_actual[i]==y_hat[i]==0:
               TN += 1
            if y_hat[i]==0 and y_actual[i]!=y_hat[i]:
               FN += 1
    
        return(TP, FP, TN, FN)
    

    从这里我认为您将能够计算您的兴趣率,以及其他性能指标,如特异性和敏感性。

    【讨论】:

    【解决方案3】:

    根据 scikit-learn 文档,

    http://scikit-learn.org/stable/modules/generated/sklearn.metrics.confusion_matrix.html#sklearn.metrics.confusion_matrix

    根据定义,混淆矩阵 C 使得 C[i, j] 等于已知在组 i 中但预测在组 j 中的观察数。

    因此在二元分类中,真负数为C[0,0],假负数为C[1,0],真正数为C[1,1],假正数为C[0,1]

    CM = confusion_matrix(y_true, y_pred)
    
    TN = CM[0][0]
    FN = CM[1][0]
    TP = CM[1][1]
    FP = CM[0][1]
    

    【讨论】:

    • 如果只有一个组,这会给你一个索引越界错误。
    【解决方案4】:

    您可以从混淆矩阵中获取所有参数。 混淆矩阵(即2X2矩阵)的结构如下(假设第一个索引与正标签相关,行与真标签相关):

    TP|FN
    FP|TN
    

    所以

    TP = cm[0][0]
    FN = cm[0][1]
    FP = cm[1][0]
    TN = cm[1][1]
    

    更多详情https://en.wikipedia.org/wiki/Confusion_matrix

    【讨论】:

    • 在我的例子中,混淆矩阵不是 2x2,而是 3x3 或 4x4。例如,我可以得到这两个数组:y_predicted:[0 0 0 0 0 1 1 2 0 2 2 3 2 2 2 2] y_true: [0 0 0 0 0 1 1 2 2 2 2 2 2 2 2 2] 并且我得到这个混淆矩阵:[[5 0 0 0] [0 2 0 0] [1 0 7 1] [0 0 0 0]]
    • 我假设了二进制分类。您的分类器似乎有 3 或 4 个类。
    • 为此,如果您查看维基百科链接,有一个关于猫、狗和马的示例。在存在两个类别(即正面和负面)的情况下,真阳性、真阴性等的概念对我来说更有意义。对于您的情况,我不确定 TP、FP 是什么意思。您可以将 TP 视为对角线元素的总和,但我不确定。您可以假设一个分类为正而所有其他分类为负来计算 TP、FP 等,但我再次不确定。
    • 您确定没有切换 FP 和 FN 位置吗?我以为应该是[TP, FN],[FP, TN]。这也是维基百科页面上显示的内容。
    • @ChrisNielsen 是的,它已被切换 - 我已将答案编辑为正确
    【解决方案5】:

    从混淆矩阵中获得真正的正数等的唯一方法是ravel它:

    from sklearn.metrics import confusion_matrix
    
    y_true = [1, 1, 0, 0]
    y_pred = [1, 0, 1, 0]   
    
    tn, fp, fn, tp = confusion_matrix(y_true, y_pred, labels=[0, 1]).ravel()
    print(tn, fp, fn, tp)  # 1 1 1 1
    

    应该设置labels 参数以防数据仅包含一个案例,例如只有真正的肯定。正确设置 labels 可确保混淆矩阵具有 2x2 形状。

    【讨论】:

    • 如果一组中只有值,这将导致“ValueError: not enough values to unpack (expected 4, got 1)”。
    • 这似乎令人惊讶 - 你的混淆矩阵是什么样的?这可能是一个有趣的边缘情况(真实值仅代表 1 个类别)。只要有标签= 1的真实值,我认为混淆矩阵将是2x2。
    • @Hagbard 我更新了答案,这样当数据中只有一个案例时它也应该起作用。
    【解决方案6】:

    在 scikit-learn 'metrics' 库中,有一个confusion_matrix 方法可以为您提供所需的输出。

    您可以使用任何您想要的分类器。这里我以 KNeighbors 为例。

    from sklearn import metrics, neighbors
    
    clf = neighbors.KNeighborsClassifier()
    
    X_test = ...
    y_test = ...
    
    expected = y_test
    predicted = clf.predict(X_test)
    
    conf_matrix = metrics.confusion_matrix(expected, predicted)
    
    >>> print conf_matrix
    >>>  [[1403   87]
         [  56 3159]]
    

    文档:http://scikit-learn.org/stable/modules/generated/sklearn.metrics.confusion_matrix.html#sklearn.metrics.confusion_matrix

    【讨论】:

    • 迄今为止最简洁的回复
    【解决方案7】:

    我编写了一个仅使用 numpy 工作的版本。 希望对你有帮助。

    import numpy as np
    
    def perf_metrics_2X2(yobs, yhat):
        """
        Returns the specificity, sensitivity, positive predictive value, and 
        negative predictive value 
        of a 2X2 table.
    
        where:
        0 = negative case
        1 = positive case
    
        Parameters
        ----------
        yobs :  array of positive and negative ``observed`` cases
        yhat : array of positive and negative ``predicted`` cases
    
        Returns
        -------
        sensitivity  = TP / (TP+FN)
        specificity  = TN / (TN+FP)
        pos_pred_val = TP/ (TP+FP)
        neg_pred_val = TN/ (TN+FN)
    
        Author: Julio Cardenas-Rodriguez
        """
        TP = np.sum(  yobs[yobs==1] == yhat[yobs==1] )
        TN = np.sum(  yobs[yobs==0] == yhat[yobs==0] )
        FP = np.sum(  yobs[yobs==1] == yhat[yobs==0] )
        FN = np.sum(  yobs[yobs==0] == yhat[yobs==1] )
    
        sensitivity  = TP / (TP+FN)
        specificity  = TN / (TN+FP)
        pos_pred_val = TP/ (TP+FP)
        neg_pred_val = TN/ (TN+FN)
    
        return sensitivity, specificity, pos_pred_val, neg_pred_val
    

    【讨论】:

      【解决方案8】:

      以防万一有人在 MULTI-CLASS 示例中寻找相同的内容

      def perf_measure(y_actual, y_pred):
          class_id = set(y_actual).union(set(y_pred))
          TP = []
          FP = []
          TN = []
          FN = []
      
          for index ,_id in enumerate(class_id):
              TP.append(0)
              FP.append(0)
              TN.append(0)
              FN.append(0)
              for i in range(len(y_pred)):
                  if y_actual[i] == y_pred[i] == _id:
                      TP[index] += 1
                  if y_pred[i] == _id and y_actual[i] != y_pred[i]:
                      FP[index] += 1
                  if y_actual[i] == y_pred[i] != _id:
                      TN[index] += 1
                  if y_pred[i] != _id and y_actual[i] != y_pred[i]:
                      FN[index] += 1
      
      
          return class_id,TP, FP, TN, FN
      

      【讨论】:

        【解决方案9】:

        在 scikit 0.22 版本中,你可以这样做

        from sklearn.metrics import multilabel_confusion_matrix
        
        y_true = ["cat", "ant", "cat", "cat", "ant", "bird"]
        y_pred = ["ant", "ant", "cat", "cat", "ant", "cat"]
        
        mcm = multilabel_confusion_matrix(y_true, y_pred,labels=["ant", "bird", "cat"])
        
        tn = mcm[:, 0, 0]
        tp = mcm[:, 1, 1]
        fn = mcm[:, 1, 0]
        fp = mcm[:, 0, 1]
        

        【讨论】:

          【解决方案10】:

          你可以试试sklearn.metrics.classification_report如下:

          import sklearn
          y_true = [1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0]
          y_pred = [1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0]
          
          print sklearn.metrics.classification_report(y_true, y_pred)
          

          输出:

                   precision    recall  f1-score   support
          
                0       0.80      0.57      0.67         7
                1       0.50      0.75      0.60         4
          
                avg / total       0.69      0.64      0.64        11
          

          【讨论】:

            【解决方案11】:

            如果您的分类器中有多个类,您可能希望在该部分使用 pandas-ml。 pandas-ml 的混淆矩阵给出了更详细的信息。 check that

            【讨论】:

              【解决方案12】:

              我认为这两个答案都不完全正确。例如,假设我们有以下数组;
              y_actual = [1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0]

              y_predic = [1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0]

              如果我们手动计算 FP、FN、TP 和 TN 值,它们应该如下:

              FP:3 前锋:1 TP:3 总成绩:4

              但是,如果我们使用第一个答案,结果如下:

              FP:1 前锋:3 TP:3 总成绩:4

              它们不正确,因为在第一个答案中,False Positive 应该是实际为 0,但预测为 1,而不是相反。假阴性也一样。

              如果我们使用第二个答案,结果计算如下:

              FP:3 前锋:1 TP:4 总成绩:3

              真正数和真负数不正确,应该相反。

              我的计算是否正确?如果我遗漏了什么,请告诉我。

              【讨论】:

              • 我认为这个问题的最佳答案是这个:stackoverflow.com/questions/31345724/…
              • 我为这个愚蠢的问题道歉,但是scikit的混淆矩阵的真实位置如下?顶行TN | FP 和底行FN | TP?我一直在试图弄清楚哪个是哪个。也许文档也可以为像我这样的白痴编写? :-)
              【解决方案13】:
              #False positive cases
              train = pd.merge(X_train, y_train,left_index=True, right_index=True)
              y_train_pred = pd.DataFrame(y_train_pred)
              y_train_pred.rename(columns={0 :'Predicted'}, inplace=True )
              train = train.reset_index(drop=True).merge(y_train_pred.reset_index(drop=True),
              left_index=True,right_index=True)
              train['FP'] = np.where((train['Banknote']=="Forged") & (train['Predicted']=="Genuine"),1,0)
              train[train.FP != 0]
              

              【讨论】:

              • print("Genuine : Forged") print(quizData['Banknote'].value_counts()['Genuine'], ":", quizData['Banknote'].value_counts()['伪造'])
              【解决方案14】:
              def getTPFPTNFN(y_true, y_pred):
                  TP, FP, TN, FN = 0, 0, 0, 0
                  for s_true, s_pred in zip (y_true, y_pred):
                      if s_true == 1:
                          if s_pred == 1: 
                              TP += 1
                          else:
                              FN += 1
                      else:
                          if s_pred == 0:
                              TN += 1
                          else:
                              FP += 1
                  return TP, FP, TN, FN
              

              【讨论】:

                【解决方案15】:

                这很好
                来源 - https://scikit-learn.org/stable/modules/generated/sklearn.metrics.confusion_matrix.html

                tn, fp, fn, tp = confusion_matrix(y_test, predicted).ravel()
                

                【讨论】:

                  【解决方案16】:

                  #FalseNegatives

                  test = pd.merge(Variables_test, Banknote_test,left_index=True, right_index=True)
                  Banknote_test_pred = pd.DataFrame(banknote_test_pred)
                  Banknote_test_pred.rename(columns={0 :'Predicted'}, inplace=True )
                  test = test.reset_index(drop=True).merge(Banknote_test_pred.reset_index(drop=True), left_index=True, right_index=True)
                  test['FN'] = np.where((test['Banknote']=="Genuine") & (test['Predicted']=="Forged"),1,0)
                  test[test.FN != 0]
                  

                  【讨论】:

                  • gen = quizData["Banknote"].value_counts()["Genuine"] forg = quizData["Banknote"].value_counts()["Forged"] print("'Genuine'的比例' : '伪造'钞票是", gen/forg)
                  • # quizData["Banknote"].value_counts() 真品 = 0 forged = 0 for i in range(len(quizData)): if quizData.loc[i]["Banknote"] == "Genuine": 真品 += 1 else: forged += 1 print("'Genuine' : 'Forged' 钞票的比例是", true/forged)
                  • 请不要将代码添加为注释,因为它很难阅读/使用。如果您有其他代码要添加到答案中,请单击答案下方的edit 并将其直接添加到答案中。
                  【解决方案17】:

                  到目前为止,没有一个答案对我有用,因为我有时最终会得到一个只有一个条目的混淆矩阵。以下代码能够缓解此问题:

                  from sklearn.metrics import confusion_matrix
                  CM = confusion_matrix(y, y_hat)
                              
                  try:
                      TN = CM[0][0]
                  except IndexError:
                      TN = 0
                  try:
                      FN = CM[1][0]
                  except IndexError:
                      FN = 0
                  try:
                      TP = CM[1][1]
                  except IndexError:
                      TP = 0
                  try:
                      FP = CM[0][1]
                  except IndexError:
                      FP = 0
                  

                  请注意,“y”是groundtruth,“y_hat”是预测。

                  【讨论】:

                    【解决方案18】:

                    我已经尝试了一些答案,但发现它们不起作用。

                    这对我有用:

                    from sklearn.metrics import classification_report
                    
                    print(classification_report(y_test, predicted)) 
                    

                    【讨论】:

                    • 这不会显示 TP、FP、TN、FN 的数量。提问者想要什么。
                    【解决方案19】:

                    这里是调用theshell 的错误代码的修复程序(当前显示为已接受的答案):

                    def performance_measure(y_actual, y_hat):
                        TP = 0
                        FP = 0
                        TN = 0
                        FN = 0
                    
                        for i in range(len(y_hat)): 
                            if y_actual[i] == y_hat[i]==1:
                                TP += 1
                            if y_hat[i] == 1 and y_actual[i] == 0:
                                FP += 1
                            if y_hat[i] == y_actual[i] == 0:
                                TN +=1
                            if y_hat[i] == 0 and y_actual[i] == 1:
                                FN +=1
                    
                        return(TP, FP, TN, FN)
                    

                    【讨论】:

                      猜你喜欢
                      • 2021-11-15
                      • 2016-02-03
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2018-04-22
                      • 2021-12-14
                      • 2017-06-08
                      相关资源
                      最近更新 更多