ロジスティック回帰による分類性能の確認

【概要】ロジスティック回帰による二値分類の性能評価を確認する。混同行列、AUC-ROC、分類レポートによる評価手法。Irisデータセット(特徴量が明確で分類境界が適度に複雑な標準的二値分類問題)を使用し、異なる評価指標の意味と解釈方法を確認する。



目次

概要

主要技術: ロジスティック回帰(Logistic Regression)

出典: Hosmer, D. W., & Lemeshow, S. (2013). Applied Logistic Regression (3rd ed.). Wiley.

理論的背景: ロジスティック回帰は線形回帰をシグモイド関数(σ(z) = 1/(1+e^(-z)))で変換した確率的分類手法である。線形結合z = β₀ + β₁x₁ + β₂x₂ + ...を0-1の確率値に変換し、最尤推定法によりパラメータを学習する。

特徴: 特徴量の係数から判断根拠を解釈でき、確率値を出力するため閾値調整が可能である。医療診断システム、マーケティング予測、品質管理の分野で活用される。

データセット選択理由: Irisデータセットは特徴量が明確で二値分類の学習に適したデータセットである。

学習目標: 混同行列、AUC-ROC、分類レポートによる多角的な性能評価を通じて、分類器の強みと弱点を定量的に把握する。異なる評価指標の違いを理解し、分類問題における評価手法の選択基準を確認する。

評価指標

混同行列: [[TN, FP], [FN, TP]]形式。正解率 = (TP+TN)/(TP+TN+FP+FN)

Precision(適合率): TP/(TP+FP) - 予測陽性の正解率

Recall(再現率): TP/(TP+FN) - 実際陽性の検出率

F1-score: 2×(Precision×Recall)/(Precision+Recall) - 両者の調和平均

AUC-ROC: 0.5=ランダム、0.7=実用下限、0.8=良好、0.9=優秀の判断基準

実務判断基準: 医療診断では再現率重視(見逃し回避)、スパム検出では適合率重視(誤判定回避)。AUC≥0.8で実用化検討、AUC≥0.9で高精度システムとして運用可能。

事前準備

Python, Windsurfをインストールしていない場合の手順(インストール済みの場合は実行不要)。

  1. 管理者権限でコマンドプロンプトを起動(手順:Windowsキーまたはスタートメニュー > cmd と入力 > 右クリック > 「管理者として実行」)し、以下を実行する。
  2. 以下のコマンドをそれぞれ実行する(winget コマンドは1つずつ実行)。

REM Python をシステム領域にインストール
winget install --scope machine --id Python.Python.3.12 -e --silent
REM Windsurf をシステム領域にインストール
winget install --scope machine --id Codeium.Windsurf -e --silent
REM Python のパス設定
set "PYTHON_PATH=C:\Program Files\Python312"
set "PYTHON_SCRIPTS_PATH=C:\Program Files\Python312\Scripts"
echo "%PATH%" | find /i "%PYTHON_PATH%" >nul
if errorlevel 1 setx PATH "%PATH%;%PYTHON_PATH%" /M >nul
echo "%PATH%" | find /i "%PYTHON_SCRIPTS_PATH%" >nul
if errorlevel 1 setx PATH "%PATH%;%PYTHON_SCRIPTS_PATH%" /M >nul
REM Windsurf のパス設定
set "WINDSURF_PATH=C:\Program Files\Windsurf"
if exist "%WINDSURF_PATH%" (
    echo "%PATH%" | find /i "%WINDSURF_PATH%" >nul
    if errorlevel 1 setx PATH "%PATH%;%WINDSURF_PATH%" /M >nul
)

必要パッケージのインストール

コマンドプロンプトを管理者として実行(手順:Windowsキーまたはスタートメニュー > cmd と入力 > 右クリック > 「管理者として実行」)し、以下を実行する:

pip install scikit-learn matplotlib seaborn japanize-matplotlib numpy

プログラムコード


# プログラム名: ロジスティック回帰による二値分類性能評価システム
# 特徴技術名: scikit-learn LogisticRegression
# 出典: Pedregosa, F., et al. (2011). Scikit-learn: Machine learning in Python. Journal of Machine Learning Research, 12, 2825-2830.
# 特徴機能: 確率的二値分類と多角的性能評価(LogisticRegressionのpredict_proba()により確率出力が可能で、ROC-AUC等の確率ベース評価指標と混同行列による詳細な分類性能分析を実現)
# 学習済みモデル: なし(Irisデータセットで新規学習)
# 方式設計:
#   - 関連利用技術:
#     - matplotlib (グラフ描画、混同行列とROC曲線の可視化)
#     - seaborn (統計的可視化、ヒートマップ表示)
#     - numpy (数値計算、配列操作)
#     - japanize-matplotlib (日本語表示対応)
#   - 入力と出力: 入力: なし(内蔵Irisデータセット使用)、出力: 分類性能評価結果のテキスト表示とグラフ表示
#   - 処理手順: 1)Irisデータセットから2クラス抽出、2)訓練・テストデータ分割、3)ロジスティック回帰学習、4)予測と確率推定、5)混同行列・AUC・分類レポート計算、6)結果可視化
#   - 前処理、後処理: 前処理: 3クラスから2クラスへの変換(クラス0を除外)、後処理: 混同行列ヒートマップとROC曲線の描画
#   - 追加処理: なし
#   - 調整を必要とする設定値: RANDOM_SEED (再現性のための乱数シード、デフォルト42)、TEST_SIZE (テストデータの割合、デフォルト0.25)
# 将来方策: RANDOM_SEEDを複数値で実行し、性能の安定性を評価する交差検証機能の実装
# その他の重要事項: Irisデータセットの3クラスから2クラス(versicolor vs virginica)に制限して二値分類を実施
# 前準備: pip install scikit-learn matplotlib seaborn japanize-matplotlib numpy

import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import japanize_matplotlib
from sklearn.datasets import load_iris
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix, classification_report, roc_auc_score, roc_curve
import time

# 定数定義
RANDOM_SEED = 42  # 再現性のための乱数シード
TEST_SIZE = 0.25  # テストデータの割合
FIGURE_SIZE = (12, 4)  # グラフサイズ
ENCODING = 'utf-8'  # ファイルエンコーディング
RESULT_FILE = 'result.txt'  # 結果保存ファイル名
COLOR_ROC = 'darkorange'  # ROC曲線の色
COLOR_BASELINE = 'navy'  # ベースライン(ランダム分類)の色
COLOR_HEATMAP = 'Blues'  # ヒートマップのカラーマップ
DISPLAY_INTERVAL = 1  # 表示間隔(秒)

# プログラム開始時の表示
print('='*60)
print('ロジスティック回帰による二値分類性能評価システム')
print('='*60)
print('概要: Irisデータセットを用いてロジスティック回帰の分類性能を評価します')
print('処理内容: データ準備→学習→評価→可視化')
print('='*60)
print()

# 結果記録用リスト
results = []

def record_result(message):
    """結果を記録し、表示"""
    timestamp = time.strftime('%H:%M:%S')
    line = f'[{timestamp}] {message}'
    results.append(line)
    print(line)

# データセット準備
record_result('データセット準備開始')
X, y = load_iris(return_X_y=True)
record_result(f'元データ形状: X={X.shape}, y={y.shape}')
record_result(f'クラス分布: {np.bincount(y)}')

# 2クラス制限(versicolor vs virginica)
mask = y != 0
X, y = X[mask], y[mask]
y = y - 1
record_result(f'2クラス制限後: X={X.shape}, y={y.shape}')
record_result(f'2クラス分布: {np.bincount(y)} (0: versicolor, 1: virginica)')

# データ分割
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=TEST_SIZE, random_state=RANDOM_SEED)
record_result(f'訓練データ: {X_train.shape}, テストデータ: {X_test.shape}')

# メイン処理
record_result('学習プロセス開始')
model = LogisticRegression(random_state=RANDOM_SEED)
model.fit(X_train, y_train)
record_result('ロジスティック回帰モデル学習完了')
record_result(f'学習済み係数(最初の2特徴量): {model.coef_[0][:2].round(3)}')

record_result('予測・評価プロセス開始')
y_pred = model.predict(X_test)
y_prob = model.predict_proba(X_test)[:, 1]
record_result(f'予測完了: {len(y_pred)}件')
record_result(f'確率値範囲: {y_prob.min():.3f} - {y_prob.max():.3f}')

# 評価指標計算
cm = confusion_matrix(y_test, y_pred)
auc = roc_auc_score(y_test, y_prob)
report = classification_report(y_test, y_pred)
accuracy = (cm[0,0] + cm[1,1]) / cm.sum()

# 結果出力
record_result('評価指標計算完了')
record_result(f'混同行列: [[{cm[0,0]}, {cm[0,1]}], [{cm[1,0]}, {cm[1,1]}]]')
record_result(f'正解率: {accuracy:.3f}')
record_result(f'AUC-ROC: {auc:.3f}')

perf_level = '0.7以下' if auc <= 0.7 else '0.7-0.8' if auc <= 0.8 else '0.8以上'
record_result(f'AUC範囲: {perf_level}')

# 詳細レポート
print('\n' + '='*50)
print('         詳細評価レポート')
print('='*50)
print('分類レポート:')
print(report)

# 総合評価
record_result('総合評価')
record_result(f'データ: {len(y_test)}件のテストデータで評価')
record_result(f'正解率: {accuracy:.1%} ({cm[0,0] + cm[1,1]}/{cm.sum()}件正解)')
record_result(f'AUC値: {auc:.3f} ({perf_level}範囲)')

# 可視化
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=FIGURE_SIZE)

sns.heatmap(cm, annot=True, fmt='d', cmap=COLOR_HEATMAP, ax=ax1)
ax1.set_title('混同行列')
ax1.set_xlabel('予測値')
ax1.set_ylabel('実際値')

fpr, tpr, _ = roc_curve(y_test, y_prob)
ax2.plot(fpr, tpr, color=COLOR_ROC, lw=2, label=f'ROC曲線 (AUC = {auc:.3f})')
ax2.plot([0, 1], [0, 1], color=COLOR_BASELINE, lw=2, linestyle='--', label='ランダム分類')
ax2.set_xlim([0.0, 1.0])
ax2.set_ylim([0.0, 1.05])
ax2.set_xlabel('偽陽性率')
ax2.set_ylabel('真陽性率')
ax2.set_title('ROC曲線')
ax2.legend(loc='lower right')
ax2.grid(True)

plt.tight_layout()
plt.show()

record_result('可視化完了: 混同行列ヒートマップ + ROC曲線')

# 1秒間隔での結果表示
print('\n1秒間隔での結果表示:')
for i, line in enumerate(results):
    print(f'{i+1}: {line}')
    time.sleep(DISPLAY_INTERVAL)

# 結果をファイルに保存
with open(RESULT_FILE, 'w', encoding=ENCODING) as f:
    for line in results:
        f.write(line + '\n')
print(f'\n{RESULT_FILE}に保存しました')

使用方法

  1. 上記のプログラムを実行する
  2. 実行結果として以下が表示される:
    • データセット情報とクラス分布
    • 学習プロセスの進行状況
    • 評価指標(混同行列、AUC-ROC、分類レポート)
    • 混同行列とROC曲線のグラフ

実験・探求のアイデア

基本実験

応用実験

発展的探求

  1. 閾値調整実験:predict_proba()の結果を使い、0.3、0.7の異なる閾値(分類判定の境界値)で分類した場合の精度・再現率の変化を観察
  2. 係数解釈実験:model.coef_を全て表示し、どの特徴量が分類に最も影響するかを特定
  3. 学習曲線実験:訓練データ量を段階的に増加させ、性能がどの時点で収束するかを検証
  4. 外れ値影響実験:意図的に極値データを追加した場合の性能劣化度合いを測定
  5. アルゴリズム比較実験:異なる分類アルゴリズム(SVM:サポートベクターマシン、決定木、ランダムフォレスト)との性能比較