[機械学習のはじめ方] Part13: ロジスティック回帰の仕組みと応用

機械学習

機械学習の分類問題に取り組む際、最初に学ぶアルゴリズムの一つがロジスティック回帰です。名前に「回帰」とついていますが、これは確率を予測し、その結果に基づいてデータを分類するために使われる手法です。特に「はい」か「いいえ」、「成功」か「失敗」のような2つのカテゴリ(二値分類)に分ける問題でよく用いられます。

線形回帰が連続的な数値を予測するのに対し、ロジスティック回帰はある事象が起こる確率(0から1の間)を予測します。例えば、メールがスパムである確率、顧客が商品を購入する確率などを知りたい場合に活躍します。

この記事では、ロジスティック回帰がどのように確率を予測し分類を行うのか、その基本的な仕組みから、Pythonのライブラリscikit-learnを使った実装例、そして実際の応用例まで、初学者の方にも分かりやすく解説していきます。💪

ロジスティック回帰の仕組み

ロジスティック回帰は、主に以下のステップで確率を計算し、分類を行います。

  1. 線形結合の計算: まず、入力される特徴量(説明変数)にそれぞれ重みを掛けて足し合わせます。これは線形回帰と同じ計算です。
    z = w_1 * x_1 + w_2 * x_2 + ... + w_n * x_n + b
    ここで、x_iはi番目の特徴量、w_iはその重み、bはバイアス(切片)です。
  2. シグモイド関数による確率への変換: 次に、線形結合で計算された値 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. 確率の解釈と分類: シグモイド関数の出力値は、特定のクラス(例えばクラス1)に属する確率 P(Y=1|X) として解釈されます。この確率に基づいて、最終的な分類を行います。一般的には、閾値(しきいち)を0.5に設定し、
    • 確率が0.5以上ならクラス1
    • 確率が0.5未満ならクラス0
    のように分類します。この閾値は、目的に応じて調整することもあります。
  2. モデルの学習(パラメータの最適化): では、適切な重み 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つのカテゴリに分けられるような問題であれば、多くの場面でロジスティック回帰が基礎的な分析手法として用いられています。

メリットとデメリット

ロジスティック回帰には、以下のようなメリットとデメリットがあります。

👍 メリット

  • 実装が比較的簡単: アルゴリズムがシンプルで、多くのライブラリで容易に実装できます。
  • 解釈性が高い: 各特徴量の重み(係数)を見ることで、どの特徴量が結果にどの程度影響を与えているかを理解しやすいです。
  • 確率で出力される: 結果が確率で得られるため、予測の確信度を知ることができます。閾値を調整することで、ビジネス要件に合わせた判断が可能です。
  • 計算コストが低い: 学習や予測に必要な計算量が比較的少なく、大規模なデータセットにも適用しやすい場合があります。
  • 線形分離可能な問題に強い: データが線形(直線や平面)で分離できる場合に、良好な性能を発揮します。

👎 デメリット

  • 非線形な関係に弱い: 基本的に線形な決定境界しか作れないため、複雑な関係性を持つデータの分類精度は低くなることがあります。(カーネル法などの拡張もあります)
  • 特徴量エンジニアリングが重要: モデルの性能は入力する特徴量に大きく依存するため、適切な特徴量の選択や作成(特徴量エンジニアリング)が重要になることがあります。
  • 外れ値の影響を受けやすい場合がある: 他の線形モデルと同様に、外れ値に影響される可能性があります。
  • 多クラス分類への拡張: 基本は二値分類ですが、多クラス分類に拡張することも可能です(例:One-vs-Rest)。ただし、他の多クラス分類に特化したアルゴリズムの方が性能が良い場合もあります。

まとめ

今回は、機械学習の基本的な分類アルゴリズムであるロジスティック回帰について、その仕組みPythonでの実装応用例、そしてメリット・デメリットを見てきました。

ロジスティック回帰は、多くのより複雑なアルゴリズムの基礎ともなる重要な概念です。この仕組みを理解することで、他の機械学習モデルへの理解も深まるでしょう。

次は、k近傍法(KNN)や決定木など、他の教師あり学習モデルについても学んでいきましょう!🚀

コメント

タイトルとURLをコピーしました