機械学習の分類問題に取り組む際、最初に学ぶアルゴリズムの一つがロジスティック回帰です。名前に「回帰」とついていますが、これは確率を予測し、その結果に基づいてデータを分類するために使われる手法です。特に「はい」か「いいえ」、「成功」か「失敗」のような2つのカテゴリ(二値分類)に分ける問題でよく用いられます。
線形回帰が連続的な数値を予測するのに対し、ロジスティック回帰はある事象が起こる確率(0から1の間)を予測します。例えば、メールがスパムである確率、顧客が商品を購入する確率などを知りたい場合に活躍します。
この記事では、ロジスティック回帰がどのように確率を予測し分類を行うのか、その基本的な仕組みから、Pythonのライブラリscikit-learn
を使った実装例、そして実際の応用例まで、初学者の方にも分かりやすく解説していきます。💪
ロジスティック回帰の仕組み
ロジスティック回帰は、主に以下のステップで確率を計算し、分類を行います。
- 線形結合の計算: まず、入力される特徴量(説明変数)にそれぞれ重みを掛けて足し合わせます。これは線形回帰と同じ計算です。
z = w_1 * x_1 + w_2 * x_2 + ... + w_n * x_n + b
ここで、x_i
はi番目の特徴量、w_i
はその重み、b
はバイアス(切片)です。 - シグモイド関数による確率への変換: 次に、線形結合で計算された値
z
をシグモイド関数(ロジスティック関数)という特殊な関数に通します。
💡 シグモイド関数とは?
シグモイド関数は、入力された値を0から1の間の確率値に変換する関数です。数式で書くと以下のようになります。
σ(z) = 1 / (1 + exp(-z))
ここで exp(-z)
はネイピア数 e
の -z 乗 (e^-z
) を意味します。
この関数の特徴は以下の通りです。
- 入力
z
がどんな値でも、出力は必ず0から1の間に収まる。 - 入力
z
が大きくなるほど出力は1に近づき、小さくなるほど0に近づく。 - 入力
z
が0のとき、出力はちょうど0.5になる。 - 滑らかなS字カーブを描く。
- 微分可能であり、勾配降下法などの最適化アルゴリズムで使いやすい。
この「0から1の間に出力される」性質が、結果を確率として解釈するのに非常に都合が良いのです。
- 確率の解釈と分類: シグモイド関数の出力値は、特定のクラス(例えばクラス1)に属する確率
P(Y=1|X)
として解釈されます。この確率に基づいて、最終的な分類を行います。一般的には、閾値(しきいち)を0.5に設定し、- 確率が0.5以上ならクラス1
- 確率が0.5未満ならクラス0
- モデルの学習(パラメータの最適化): では、適切な重み
w
とバイアスb
はどうやって見つけるのでしょうか? モデルが予測した確率と実際の正解ラベル(0か1)との「ずれ」を測る損失関数を定義し、その値が最小になるようにパラメータを調整していきます。ロジスティック回帰では、交差エントロピー誤差(Cross-Entropy Loss)という損失関数がよく使われます。この損失関数を最小化するために、勾配降下法などの最適化アルゴリズムが用いられます。
🤔 なぜ交差エントロピー誤差を使うの?
線形回帰では二乗誤差が使われましたが、ロジスティック回帰で二乗誤差を使うと、最適化したい損失関数の形が複雑(非凸関数)になり、最適解を見つけにくくなる問題があります。一方、交差エントロピー誤差を使うと、損失関数が凸関数となり、勾配降下法などで効率的に最適解を見つけやすくなります。また、交差エントロピーは情報理論の観点から、2つの確率分布(真の分布と予測分布)の「近さ」を測る指標としても解釈でき、確率を扱うロジスティック回帰に適しています。
Python (scikit-learn) による実装例
Pythonの機械学習ライブラリscikit-learn
を使うと、ロジスティック回帰を簡単に実装できます。ここでは、簡単なサンプルデータ(例:勉強時間から試験の合否を予測)で試してみましょう。
# 必要なライブラリのインポート
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
# サンプルデータの生成 (勉強時間と合否)
# 勉強時間 (時間)
hours_studied = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]).reshape(-1, 1)
# 合否 (0: 不合格, 1: 合格) - 10時間あたりを境にするイメージ
passed = np.array([0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1])
# 訓練データとテストデータに分割 (今回は簡単化のため全データを使用)
# X_train, X_test, y_train, y_test = train_test_split(hours_studied, passed, test_size=0.3, random_state=42)
# ロジスティック回帰モデルの準備
# random_stateは結果を再現可能にするためのシード値
model = LogisticRegression(random_state=0)
# モデルの学習
model.fit(hours_studied, passed)
# 新しいデータで予測
# 例: 7.5時間勉強した場合と15.5時間勉強した場合
new_hours = np.array([[7.5], [15.5]])
predicted_pass_fail = model.predict(new_hours)
predicted_probability = model.predict_proba(new_hours)
print(f"勉強時間 {new_hours[0][0]} 時間の場合の予測: {'合格' if predicted_pass_fail[0] == 1 else '不合格'}")
print(f" -> 各クラスの確率 (不合格, 合格): {predicted_probability[0]}")
print(f"勉強時間 {new_hours[1][0]} 時間の場合の予測: {'合格' if predicted_pass_fail[1] == 1 else '不合格'}")
print(f" -> 各クラスの確率 (不合格, 合格): {predicted_probability[1]}")
# 学習結果の確認 (係数と切片)
print(f"\nモデルの係数 (w): {model.coef_}")
print(f"モデルの切片 (b): {model.intercept_}")
# 決定境界(確率が0.5になる点)を可視化(オプション)
# z = w*x + b = 0 となる x を求める
# decision_boundary = -model.intercept_ / model.coef_[0][0]
# print(f"決定境界 (確率0.5の勉強時間): {decision_boundary[0]:.2f} 時間")
# plt.scatter(hours_studied, passed, color='blue', zorder=20, label='実績データ')
# X_plot = np.linspace(0, 21, 300).reshape(-1, 1)
# y_plot_proba = model.predict_proba(X_plot)[:, 1] # 合格する確率
# plt.plot(X_plot, y_plot_proba, color='red', linewidth=3, label='ロジスティック回帰モデル (合格確率)')
# plt.axhline(0.5, color='grey', linestyle='--', label='閾値 0.5')
# plt.xlabel('勉強時間 (時間)')
# plt.ylabel('合否 (0:不合格, 1:合格) / 合格確率')
# plt.title('勉強時間と合否のロジスティック回帰')
# plt.yticks([0, 0.5, 1], ['0 (不合格)', '0.5', '1 (合格)'])
# plt.legend()
# plt.grid(True)
# plt.show()
このコードでは、LogisticRegression
クラスを使ってモデルを作成し、fit
メソッドで学習させています。predict
メソッドはクラス(0か1)を予測し、predict_proba
メソッドは各クラスに属する確率を返します。
実行結果の例:
勉強時間 7.5 時間の場合の予測: 不合格
-> 各クラスの確率 (不合格, 合格): [0.6157628 0.3842372]
勉強時間 15.5 時間の場合の予測: 合格
-> 各クラスの確率 (不合格, 合格): [0.03439277 0.96560723]
モデルの係数 (w): [[0.51988113]]
モデルの切片 (b): [-4.3717446]
7.5時間勉強した場合、不合格になる確率が約61.6%と予測され、クラス分類としては「不合格」になります。一方、15.5時間勉強した場合は、合格する確率が約96.6%と予測され、「合格」と分類されます。
ロジスティック回帰の応用例 🚀
ロジスティック回帰は、そのシンプルさと解釈のしやすさから、様々な分野で広く応用されています。
- 迷惑メールフィルタリング: メールに含まれる単語や送信元情報などから、そのメールがスパムメールである確率を予測し、分類します。
- 医療診断支援: 患者の検査値や症状などのデータから、特定の病気(例:がん、糖尿病)を発症している確率を予測し、診断の補助として利用されます。
- 金融(信用スコアリング): 顧客の属性情報(年齢、収入、借入履歴など)から、ローン返済が滞る(デフォルトする)確率を予測し、融資判断の参考にします。
- マーケティング(顧客行動予測): 顧客のウェブサイト閲覧履歴や購買履歴から、特定の商品を購入する確率や、キャンペーンに反応する確率を予測し、ターゲティング広告などに活用します。
- 不正検知: クレジットカード取引のデータから、その取引が不正利用である確率を予測します。
- サブスクリプションサービスの解約予測: 顧客の利用状況や属性から、サービスを解約する確率を予測し、解約防止策を検討します。
これらはほんの一例であり、結果が2つのカテゴリに分けられるような問題であれば、多くの場面でロジスティック回帰が基礎的な分析手法として用いられています。
メリットとデメリット
ロジスティック回帰には、以下のようなメリットとデメリットがあります。
まとめ
今回は、機械学習の基本的な分類アルゴリズムであるロジスティック回帰について、その仕組み、Pythonでの実装、応用例、そしてメリット・デメリットを見てきました。
- ロジスティック回帰は、分類問題(特に二値分類)に使われる教師あり学習アルゴリズム。
- 線形結合の結果をシグモイド関数に通すことで、0から1の確率を出力する。
- 出力された確率と閾値(通常0.5)を比較して、クラスを決定する。
- モデルの学習には、交差エントロピー誤差を損失関数として用いることが多い。
- 実装が簡単で解釈性が高く、様々な分野で応用されている。
- 線形分離可能なデータには強いが、複雑な非線形データには限界がある。
ロジスティック回帰は、多くのより複雑なアルゴリズムの基礎ともなる重要な概念です。この仕組みを理解することで、他の機械学習モデルへの理解も深まるでしょう。
次は、k近傍法(KNN)や決定木など、他の教師あり学習モデルについても学んでいきましょう!🚀
コメント