[Python] ロジスティック回帰分析によるコロナ診断

バックエンド技術

CRAIDでブリッジエンジニアをしているYoshimuraです。
普段ともに仕事しているセブ在住エンジニアのJamesさんが投稿したテック記事を翻訳・加筆しましたので、当記事で紹介いたします。

英語を勉強されている方は、ぜひ当記事で日本語で理解した上で、英語記事を読んで頂くと分かり易いと思います。ご一緒にどうぞ。
翻訳元記事(オフショア子会社Full Speed Technologiesの技術ブログ)

なお、当記事内で扱うデータやコードは章末にリンクがございます。目次からご確認下さい。

ロジスティック回帰分析とは

ロジスティック回帰分析は、最も一般的な教師あり学習(機械学習)の 1 つです。「はい」か「いいえ」、「真」か「偽」など、発生するバイナリ(2進数)の事象を予測するために使用します。

但し、当記事では2つ以上の分類を扱います。モデルに入力するデータセットは、数値データとテキストデータの組み合わせとなります。分析の結果、各分類を反映した確率を表す数値が出力されます。

サムネイル

加筆:上の図のように、年齢、性別、給与からYes/Noの確率を予想する分析です。専門的な用語で説明すると、教師あり学習では、データセットの要因(説明変数)からバイナリの結果(目的変数)が起こる確立を予測する統計手法で、多変量解析手法の1つです。人間が予めデータセットを分析し、バイナリのラベルを定めた上で、機械に学習させ、データセットに対するバイナリの予測を行うモデルを構築します。おしゃれさ、かっこよさ、優しさなどを数値化して、とある誰かさんが彼女と付き合えるか確率を予想するイメージです。ほんまかいなw

診断に扱うデータセット

背景として、教師あり機械学習は、モデルに与えるデータセットに入力と出力の両方がある種類の機械学習です。今回使用するサンプル データには、入力と出力の両方が含まれています。ロジスティック回帰分析は、ターゲット変数 (説明変数)がカテゴリ分けされていたり、分類されている場合に使用する事ができます。仕様例としては、電子メールがスパムであるかどうかの検出であったり、出力が分類 A、 B、 C などのパターンに分かれるような問題の検出などです。

当記事では、列数の少ないデータに基づいて、Python を使用し単純なロジスティック回帰モデルを実装・作成します。現実の分析では、通常、更に多くの列数のデータを利用します。

サムネイル

今回使用する上記データには 7 つの列があります。加筆:左から体温、体の痛み、鼻水、自宅の同居人数、在宅勤務、コロナワクチン摂取済み、診察結果(インフルエンザ、新型コロナ感染、風邪)の列となっております。

機械学習において、最初の 6 列は入力として使用し、最後の列 (予測) は出力として使用します。当データは単なる模擬データであり、医療施設提供のものではありません。当データのCSVには75 行分のデータがあり、このデモンストレーションには十分ですが、現実世界の分析設定や研究には恐らく不十分です。

Pythonによるロジスティック回帰分析

入力データ準備とデータ傾向の理解

ライブラリインポート

ロジスティック回帰モデルに当データを入力する為に、まず必要なライブラリをインポートします。

import pandas as pd
import matplotlib.pyplot as plt
from sklearn.linear_model import LogisticRegression

pandasは、CSVデータの読み込みに使用します。加筆:pandasはPythonのデータ解析用ライブラリ。

pyplotは、データ傾向の理解目的で一部のデータを視覚化するためにのみ使用されます。加筆matplotlibはPythonのグラフ描画用ライブラリ。

sklearn の LogisticRegressionは、ロジスティック回帰モデルの作成に使用するライブラリです。加筆:scikit-learn (sklearn)はPythonの機械学習ライブラリ。

CSVの読み込み

dataset = pd.read_csv('flu_covid_colds_activity.csv')

flu_covid_colds_activity.csvというCSVからデータ全体をdataset変数に取り込みます。dataset変数には、6 つの全入力列と 1 つの出力列が含まれるようになりました。

データ傾向の理解

plt.ylabel('Prognosis')
plt.xlabel('Temperature')
plt.scatter(dataset.temperature, dataset.prognosis)
plt.show()
plt.ylabel('Prognosis')
plt.xlabel('Num People at Home')
plt.scatter(dataset.num_people_at_home, dataset.prognosis)
plt.show()

このデモでは、2 つのグラフを表示します。1 つのグラフは診察結果(Y列)と体温(X列)の関係を示し、もう 1 つのグラフは診察結果(Y列)と患者の自宅の同居人数(X列)の関係を示します。

加筆:ylabelやxlabelは表のラベル設定を行います。scatter関数にdataset変数の体温と診察結果を渡して、show関数でグラフが表示されます。2つ目のグラフも同様で、簡単にグラフが表示できますね!

サムネイル

2 つのグラフから、インフルエンザ、風邪、新型コロナ感染の 3 つの出力分類間にクラスターがあることがはっきりとわかります。他の入力と予測出力列でもグラフ化できますが、今のところはこれで十分に傾向が見て取れます。

テキストデータの数値化

# Convert strings to numeric
dataset.body_aches = dataset.body_aches.replace(to_replace=['no', 'yes'], value=[0, 1])
dataset.runny_nose = dataset.runny_nose.replace(to_replace=['no', 'yes'], value=[0, 1])
dataset.working_at_home = dataset.working_at_home.replace(to_replace=['no', 'yes'], value=[0, 1])
dataset.covid_vaccinated = dataset.covid_vaccinated.replace(to_replace=['no', 'yes'], value=[0, 1])
dataset.prognosis = dataset.prognosis.replace(to_replace=['flu', 'covid', 'colds'], value=[0, 1, 2])

LogisticRegression関数では機械学習中に文字列値 (yes/no) が許可されない為、数値形式 (いいえ→ 0、はい→ 1など)に変換します。上記コードによりyes/no 値を持つすべての入力列が数値に変換されました。また、出力の診察結果列も数値に変換されました。(インフルエンザ→ 0、新型コロナ感染→ 1、風邪→2)

加筆:replace関数に変換前と変換後の配列を渡す事で、dataset変数のbody_achesを変換し、元のbody_achesを上書いてますね。

サムネイル

上図は変換後のdataset変数の内容です。すべての文字の列が数値に変換されました。

また、後ほど分析対象のデータに対しても入力データの文字列を数値に変換します。

ロジスティック回帰モデル作成

# Create the Logistic Regression Model
model = LogisticRegression(max_iter=500)
model.fit(dataset[[
   'temperature',
   'body_aches',
   'runny_nose',
   'num_people_at_home',
   'working_at_home',
   'covid_vaccinated'
]], dataset.prognosis)

LogisticRegression関数を使用してモデルを作成します。max_iter パラメーターは、モデルが機械学習する反復回数を定義します。データ行が数行しかない為、このパラメーターに値 500 を指定し、反復して学習するようにしました。

model.fit関数(加筆:ロジスティック回帰モデルの重みを学習)には2つのパラメータがあります。最初のパラメータは 6 列のデータを含む入力用で、2つ目のパラメータは診察結果の出力用です。

テスト用データ準備

# Test the model
test_temperature = 39
test_body_aches = 'yes'
test_runny_nose = 'yes'
test_num_people_at_home = 3
test_working_at_home = 'no'
test_covid_vaccinated = 'no'

ロジスティック回帰モデルの作成と機械学習が完了したので、テストしましょう。CSV の 3 行目の値を使用してモデルをテストします。この行の診察結果はサンプルデータ同様の新型コロナ感染であれば正解ですね。

# Convert the test values to numeric
test_body_aches = 1 if test_body_aches == 'yes' else 0
test_runny_nose = 1 if test_runny_nose == 'yes' else 0
test_working_at_home = 1 if test_working_at_home == 'yes' else 0
test_covid_vaccinated = 1 if test_covid_vaccinated == 'yes' else 0

この変換コードは、モデルの機械学習の書き方と少し異なりますね。大切なのは、モデル構築時と同じようにno→0、yes→1 はとなるように変換することです。

ロジスティック回帰分析の実行

output = model.predict_proba([[
   test_temperature,
   test_body_aches,
   test_runny_nose,
   test_num_people_at_home,
   test_working_at_home,
   test_covid_vaccinated
]])

modelのpredict_proba関数 を使用して、各出力分類の確率を計算します。出力には 3 つの分類があるため、出力には 3 つの値が含まれている必要があります。インフルエンザ→ 0、新型コロナ感染→ 1、風邪→2のように、出力列の変換を割り当てたので、それぞれの確率を出力する必要があります。これらの 3 つの出力値はテスト用データの確率を表すため、加算すると 1 になるはずです。

print("FLU\t", "{:.4f}".format(output[0][0]))
print("COVID\t", "{:.4f}".format(output[0][1]))
print("COLDS\t", "{:.4f}".format(output[0][2]))

このコードで出力をフォーマット化します。出力数値は小数点以下 4 桁に四捨五入されます。テストに使用するデータはCSV の 3 行目であり、最も高い確率で新型コロナ感染になるはずでしたね。

サムネイル

予想通り、最も確率が高いクラスは COVID 分類です。その為、この検査対象者が新型コロナに感染している確率は 0.96、つまり 96% です。インフルエンザと風邪の確率は十分に低いです。

ソースコード

当記事で使用したコードとCSVは当リポジトリに格納しております。

https://github.com/jamesnogra/SimpleLogisticRegressionPython

インストール手順を記載しております。Python 3.6 以降を搭載したPC/Macでの実行を想定しております。

加筆:レポジトリからソースコードとローカルに落として頂き、pip/Pythonの実行環境を整えた上で、以下を実行コマンドを頂くと、当記事内で説明したpandas/matplotlib/scikit-learnのライブラリがインストールされます。

pip install -r requirements.txt;python logistic.py;



オフショア開発ならCRAID!

オフショア開発とは、システム開発業務などを海外の開発会社や海外子会社に委託することです。

CRAIDは東証プライム上場のフリービット株式会社の子会社です。CRAIDのオフショア開発拠点「フルスピードテクノロジーズ」は、当初は月間3000億ものリクエスト処理にも対応できる自社システム開発を行うためのオフショア開発部門として始まりました。各グループ会社の開発やクライアント様の受託開発やラボ型開発も多く手掛けております。

CRAIDやオフショア開発に関して、お気軽にお問い合わせください。

この記事を書いた人

米国の大学を卒業。インド財閥系IT企業でブリッジSEとして3年間勤務後、
半導体メーカーの社内SEとして、6年間システムの海外展開や運用を担当。
子供の英語教育を念頭にフィリピン移住を目指し、2022年CRAIDに入社。
現在セブ島でオフショア開発子会社の開発組織マネージャーとして勤務中。

Yoshimuraをフォローする
バックエンド技術
CRAID オフショア開発ブログ
タイトルとURLをコピーしました