2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

「検査法の正答率9割」を全列挙する

Last updated at Posted at 2021-01-26

ある感染症の感染者と非感染者を識別する問題を考えます。ある検査法において陽性・陰性という結果が出た時、検査結果は次の4種類に分類できます。

  • TP (True Positive) :検査結果が陽性と出た感染者
  • FN (False Negative) :検査結果が陰性と出た感染者
  • FP (False Positive):検査結果が陽性と出た非感染者
  • TN (True Negative) :検査結果が陰性と出た非感染者

このとき、正答率(正解率)は Accuracy = (TP + TN) / (TP + FN + FP + TN) と計算できます。

このとき、次の問題について考えてみましょう。

【問題】「正答率9割」を謳っている検査法がある。この検査法で正答率を計算した時点において、検査を受けた人の50%が感染者の場合、10%が感染者の場合、1%が感染者の場合という3つのケースに対して、陽性者が感染者である確率を推定しなさい。

この問題に答えるPythonコードを書いてみます。

日本語版 matplotlib をインストール

!pip install japanize-matplotlib
Collecting japanize-matplotlib
[?25l  Downloading https://files.pythonhosted.org/packages/aa/85/08a4b7fe8987582d99d9bb7ad0ff1ec75439359a7f9690a0dbf2dbf98b15/japanize-matplotlib-1.1.3.tar.gz (4.1MB)
[K     |████████████████████████████████| 4.1MB 4.0MB/s 
[?25hRequirement already satisfied: matplotlib in /usr/local/lib/python3.6/dist-packages (from japanize-matplotlib) (3.2.2)
Requirement already satisfied: pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1 in /usr/local/lib/python3.6/dist-packages (from matplotlib->japanize-matplotlib) (2.4.7)
Requirement already satisfied: kiwisolver>=1.0.1 in /usr/local/lib/python3.6/dist-packages (from matplotlib->japanize-matplotlib) (1.3.1)
Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.6/dist-packages (from matplotlib->japanize-matplotlib) (0.10.0)
Requirement already satisfied: python-dateutil>=2.1 in /usr/local/lib/python3.6/dist-packages (from matplotlib->japanize-matplotlib) (2.8.1)
Requirement already satisfied: numpy>=1.11 in /usr/local/lib/python3.6/dist-packages (from matplotlib->japanize-matplotlib) (1.19.5)
Requirement already satisfied: six in /usr/local/lib/python3.6/dist-packages (from cycler>=0.10->matplotlib->japanize-matplotlib) (1.15.0)
Building wheels for collected packages: japanize-matplotlib
  Building wheel for japanize-matplotlib (setup.py) ... [?25l[?25hdone
  Created wheel for japanize-matplotlib: filename=japanize_matplotlib-1.1.3-cp36-none-any.whl size=4120276 sha256=286795079465880c2c9d5d742e7259a51cb2f2923b5bf644de4121990dcccd1b
  Stored in directory: /root/.cache/pip/wheels/b7/d9/a2/f907d50b32a2d2008ce5d691d30fb6569c2c93eefcfde55202
Successfully built japanize-matplotlib
Installing collected packages: japanize-matplotlib
Successfully installed japanize-matplotlib-1.1.3

「検査法の正答率9割」を全列挙する

どのような場合に「検査法の正答率9割」になるのか、全列挙するコードはこちらになります。

import numpy as np
import matplotlib.pyplot as plt
import japanize_matplotlib 

percentage_infected = 0.1  # 検査を受けた人のうち感染者の割合
population_size = 100 # 検査を受けた人数
target_accuracy = 0.9 # 正答率の値

def enumerate_cases(percentage_infected, population_size, target_accuracy):
    infected = population_size * percentage_infected # 感染者の数
    notinfected = population_size * (1 - percentage_infected) # 非感染者の数
    
    case_id = 0
    for TP in range(int(infected) + 1): # 全感染者のうちのTPの数
        FN = int(infected - TP) # 全感染者のうちTPを除いた数がFN
        for TN in range(int(notinfected) + 1): # 全非感染者のうちのTNの数
            FP = int(notinfected - TN) # 全非感染者のうちTNを除いた数がFP
            accuracy = (TP+TN)/(TP+FN+FP+TN) # 正答率の計算
            if accuracy == target_accuracy: # 目的の正答率と一致したら表示
                case_id += 1
                print("Case {}".format(case_id))
                fig, axes = plt.subplots(nrows=1, ncols=3, figsize=(12, 4))
                axes[0].set_title("検査人数: {}名".format(population_size))
                axes[0].pie([TP, FN, FP, TN], counterclock=False, autopct="%.1f%%", startangle=90, 
                            labels=["TP(感染・陽性)", "FN(感染・陰性)", "FP(非感染・陽性)", "TN(非感染・陰性)"], 
                            colors=["red", "orange", "pink", "skyblue"])

                axes[1].set_title("検査結果が陽性: {}名".format(TP+FP))
                axes[1].pie([TP, FP], counterclock=False, autopct="%.1f%%", startangle=90, 
                            labels=["TP(感染・陽性)", "FP(非感染・陽性)"], colors=["red", "pink"])
                
                axes[2].set_title("検査結果が陰性: {}名".format(FN+TN))
                axes[2].pie([FN, TN], counterclock=False, autopct="%.1f%%", startangle=90, 
                            labels=["FN(感染・陰性)", "TN(非感染・陰性)"], colors=["orange", "skyblue"])
                plt.show()

50%が感染者(検査人数100人)の場合

percentage_infected = 0.5  # 検査を受けた人のうち感染者の割合
population_size = 100 # 検査を受けた人数
target_accuracy = 0.9 # 正答率の値

enumerate_cases(percentage_infected, population_size, target_accuracy)
Case 1

accuracy90_6_1.png

Case 2

accuracy90_6_3.png

Case 3

accuracy90_6_5.png

Case 4

accuracy90_6_7.png

Case 5

accuracy90_6_9.png

Case 6

accuracy90_6_11.png

Case 7

accuracy90_6_13.png

Case 8

accuracy90_6_15.png

Case 9

accuracy90_6_17.png

Case 10

accuracy90_6_19.png

Case 11

accuracy90_6_21.png

以上の11ケースが得られました。感染者・非感染者の数が拮抗している場合は、「正答率9割」はけっこう信頼できそうな気がします。

10%が感染者(検査人数100人)の場合

percentage_infected = 0.1  # 検査を受けた人のうち感染者の割合
population_size = 100 # 検査を受けた人数
target_accuracy = 0.9 # 正答率の値

enumerate_cases(percentage_infected, population_size, target_accuracy)
Case 1

accuracy90_8_1.png

Case 2

accuracy90_8_3.png

Case 3

accuracy90_8_5.png

Case 4

accuracy90_8_7.png

Case 5

accuracy90_8_9.png

Case 6

accuracy90_8_11.png

Case 7

accuracy90_8_13.png

Case 8

accuracy90_8_15.png

Case 9

accuracy90_8_17.png

Case 10

accuracy90_8_19.png

Case 11

accuracy90_8_21.png

こちらも11ケースが得られましたが、感染者の割合が10%まで少なくなると、「正答率9割」と言えども、「検査結果が陽性」の人の中の「感染者」の割合は50%に過ぎないということが分かります。

1%が感染者(検査人数1000人)の場合

percentage_infected = 0.01  # 検査を受けた人のうち感染者の割合
population_size = 1000 # 検査を受けた人数
target_accuracy = 0.9 # 正答率の値

enumerate_cases(percentage_infected, population_size, target_accuracy)
Case 1

accuracy90_12_1.png

Case 2

accuracy90_12_3.png

Case 3

accuracy90_12_5.png

Case 4

accuracy90_12_7.png

Case 5

accuracy90_12_9.png

Case 6

accuracy90_12_11.png

Case 7

accuracy90_12_13.png

Case 8

accuracy90_12_15.png

Case 9

accuracy90_12_17.png

Case 10

accuracy90_12_19.png

Case 11

accuracy90_12_21.png

検査人数1000人の場合、1%が感染したケースは11とおり考えられますが、いずれも「陽性の人が感染者である確率」はけっこう低いことが分かります。

教訓

「正答率9割」という、たったひとつの数字だけでは正しい情報は得られないので、情報提供する側にはもっとデータを開示していただきたいし、情報を受け取る側も、たったひとつの数字だけで判断しないように気をつけていただきたいと思います。

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?