73072


2つのリストがあり、一つは各患者がある病気にかかる割合を表す数値の入ったリスト、もう一つは陽性患者のインデックスを表すリストがあります。この2つのリストと閾値を比較して、真の陽性、偽の陽性、真の陰性、偽の陰性の4つのリストに分けたいと考えています。

本来、最終結果の4つのリストのデータ数の総和は本のデータ数の総和(25)に等しくあるべきであるはずですが、このコードでは異なっています。それぞれ4つのリストに入るべき条件などは書き間違いはないと思うのですが、なぜこのような結果になるのかがわかりません。どなたか解決策をおしえていただけませんか？
よろしくお願いします

以下が自分で書いたコードです。

[code]

    data = [0.0049, 0.2351, 0.8173, 0.9115, 0.8093, 0.1836, 0.2198, 0.9955, 0.3846, 0.1468, 0.9478, 0.92, 0.9127, 0.3558, 0.8828, 0.9998, 0.5782, 0.5649, 0.4276, 0.1114, 0.6143, 0.7477, 0.4198, 0.2642, 0.0728]
    cancer_id = [3,5,8,11,12,15,16,21]
    tp = []  # 真陽性
    fp = []  # 偽陽性
    tn = []  # 真陰性
    fn = []  # 偽陰性
    theta = 0.8  # 閾値
    count = 0
    
    for i in data:
        count += 1
        for id_number in cancer_id:
            if i >= theta and id_number == count:
                print("patient id {} is true positive".format(count))
                tp.append(count)
            elif i >= theta and id_number != count:
                print("patient id {} is false positive".format(count))
                fp.append(count)
            elif i < theta and id_number == count:
                print("patient id {} is false negative".format(count))
                tn.append(count)
            elif i < theta and id_number != count:
                print("patient id {} is true negative".format(count))
                fn.append(count)
    
    print(len(tp))  # 7
    print(len(fp))  # 65
    print(len(tn))  # 1
    print(len(fn))  # 127
    
[/code]


CC BY-SA 4.0
2021-01-04T12:41:37.380
73069
2021-01-04T16:20:29.723
2021-01-04T16:20:29.723
3060
43410
question
python
2つのリストを比較して条件ごとに分けたい


質問のプログラムは、以下のような構造になっています。

[code]

    for i in data: // dataリストの長さは25なので、ループは25回実行される。
        count += 1
        for id_number in cancer_id:　// cancer_idリストの長さは8なので、ループは8回実行される。
           // if i >= theta and id_number == count: で始まるif-elseのブロックでは、４つのリスト(tp,fp,tn,fn)の一つに項目が追加される（どのリストに追加されるかは、dataリストとcancer_idリストの内容により決まる）
    
[/code]

外側のforループが25回、内側のforループが8回実行されるので、  
中に入っているif-elseのブロックは 25 x 8 で、200回実行されますから、4つのリストに追加される項目の総数は200個になるはずです。

実行結果（各リストの長さ）は以下のようになっています。

> print(len(tp)) # 7  
>  print(len(fp)) # 65  
>  print(len(tn)) # 1  
>  print(len(fn)) # 127

長さの総和(4つのリストに追加された項目の総数)は、7+65+1+127で200ですから、まったく正しく事項されているとしか思えません。

『4つのリストのデータ数の総和は本のデータ数の総和(25)に等しくあるべき』と質問者が考える根拠は何ですか？


CC BY-SA 4.0
2021-01-04T13:15:26.123
73070
2021-01-04T13:15:26.123
217
73069
answer


おそらくやりたいのは以下のようなことだと思われます。  
元の処理では`cancer_id`を`for`ループで回すという処理が間違っているのではないでしょうか？

あと真陽性/偽陽性/真陰性/偽陰性の判定もおかしな感じだったので修正してみました。  
陽性患者リストに含まれるか否かが陽性/陰性を決め、その分類と計測データ範囲が合っているか否かで真/偽が決まるのでは？

[code]

    data = [0.0049, 0.2351, 0.8173, 0.9115, 0.8093, 0.1836, 0.2198, 0.9955, 0.3846, 0.1468, 0.9478, 0.92, 0.9127, 0.3558, 0.8828, 0.9998, 0.5782, 0.5649, 0.4276, 0.1114, 0.6143, 0.7477, 0.4198, 0.2642, 0.0728]
    cancer_id = [3,5,8,11,12,15,16,21]
    tp = []  # 真陽性
    fp = []  # 偽陽性
    tn = []  # 真陰性
    fn = []  # 偽陰性
    theta = 0.8  # 閾値
    
    #### enumerate()でインデックス値とデータを1回で取得。countの処理を不要とする
    for idx,value in enumerate(data):
        #### id_number と count の比較ではなくインデックス値が陽性患者リストに含まれるかを判定
        if idx in cancer_id:
            if value >= theta:
                print("patient id {} is true positive".format(idx))
                tp.append(idx)
            else:
                print("patient id {} is false positive".format(idx))
                fp.append(idx)
        else:
            if value >= theta:
                print("patient id {} is false negative".format(idx))
                fn.append(idx)
            else:
                print("patient id {} is true negative".format(idx))
                tn.append(idx)
    
    print(len(tp))  # 7   ->  4
    print(len(fp))  # 65  ->  5
    print(len(tn))  # 1   ->  4
    print(len(fn))  # 127 -> 12
    
[/code]


CC BY-SA 4.0
2021-01-04T13:58:54.917
73072
2021-01-04T14:15:09.413
2021-01-04T14:15:09.413
26370
26370
73069
answer


参考までに別解を挙げておきます。論理値(True/False)を整数値に変換(cast)して、それをリストのインデックスとしています。

[code]

    tp = []  # 真陽性
    fp = []  # 偽陽性
    tn = []  # 真陰性
    fn = []  # 偽陰性
    theta = 0.8  # 閾値
    
    lst = [fp, fn, tp, tn]
    [
      lst[int(i in cancer_id)*2+int(data[i]<theta)].append(i)
      for i in range(len(data))
    ]
    
    print(len(tp), len(fp), len(tn), len(fn))
    => 4 5 4 12
    
[/code]


CC BY-SA 4.0
2021-01-04T14:55:11.900
73074
2021-01-04T14:55:11.900
73069
answer