6. 分類モデル¶
第 6 回では、機械学習における基本的な分類(Classification)モデルについて学びます。
具体的には、ロジスティック回帰、決定木、ランダムフォレストの 3 つの分類手法を学び、実際のデータセットで実装していきます。
6.1 分類問題の基礎¶
6.1.1 2 値分類と多値分類¶
分類問題は大きく以下の 2 つに分けることができます。
graph TB
A[分類問題] --> B[2値分類<br/>Binary Classification]
A --> C[多値分類<br/>Multi-class Classification]
B --> B1[2つのクラスに分類<br/>例: スパム判定 Yes/No<br/>病気の有無 有/無]
C --> C1[3つ以上のクラスに分類<br/>例: アヤメの種類 3種<br/>手書き数字 0-9]
style A fill:#e6ccff
style B fill:#ccffcc
style C fill:#ffffcc
2 値分類(Binary Classification):
- 正解ラベルが 2 つ(Yes/No、True/False、0/1 など)
- 例:メールがスパムかどうか、病気の有無
多値分類(Multi-class Classification):
- 正解ラベルが 3 つ以上
- 例:アヤメの種類(3 種)、手書き数字(0-9 の 10 種類)
6.2 ロジスティック回帰¶
6.2.1 ロジスティック回帰とは¶
ロジスティック回帰(Logistic Regression) は、名前に「回帰」とついていますが、分類 のためのアルゴリズムです。
線形回帰では \(y = ax + b\) という式で数値を予測しましたが、ロジスティック回帰では シグモイド関数 を使って、0 から 1 の間の確率を出力します。
graph LR
A[入力<br/>x] --> B[線形結合<br/>z = w·x + b]
B --> C[シグモイド関数<br/>σz = 1/1+e⁻ᶻ]
C --> D[確率<br/>0 ≤ P ≤ 1]
D --> E[分類<br/>P ≥ 0.5 → クラス1<br/>P < 0.5 → クラス0]
style A fill:#e6f3ff
style B fill:#fff4cc
style C fill:#ffcccc
style D fill:#ffffcc
style E fill:#ccffcc
シグモイド関数
シグモイド関数は、任意の実数を 0 から 1 の間の値に変換する関数です。
- 入力が大きい正の数 → 1 に近づく
- 入力が大きい負の数 → 0 に近づく
- 入力が 0 → ちょうど 0.5
この性質により、確率を表現するのに適しています。
6.2.2 ロジスティック回帰の実装¶
scikit-learn でロジスティック回帰を実装するには、sklearn.linear_model.LogisticRegression() クラスを使用します。
import pandas as pd
import numpy as np
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
import seaborn as sns
# tipsデータセットの読み込み
tips = sns.load_dataset('tips')
# データの確認
print(tips.head())
# 特徴量とラベルの分離(チップから時間帯を予測)
X = tips[['tip']]
y = tips['time'].values # Dinne or Lunch
# データ分割
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
# ロジスティック回帰モデルの学習
model = LogisticRegression()
model.fit(X_train, y_train)
# 予測
y_pred = model.predict(X_test)
# 精度の計算
accuracy = accuracy_score(y_test, y_pred)
print(f"\n精度: {accuracy:.2%}")
total_bill tip sex smoker day time size
0 16.99 1.01 Female No Sun Dinner 2
1 10.34 1.66 Male No Sun Dinner 3
2 21.01 3.50 Male No Sun Dinner 3
3 23.68 3.31 Male No Sun Dinner 2
4 24.59 3.61 Female No Sun Dinner 4
精度: 69.39%
6.2.3 分類モデルの評価指標¶
分類問題では、回帰問題とは異なる評価指標を使います。
graph LR
A[分類モデルの評価指標] --> B[正解率<br/>Accuracy]
A --> C[適合率<br/>Precision]
A --> D[再現率<br/>Recall]
A --> E[F1スコア<br/>F1-Score]
A --> F[混同行列<br/>Confusion Matrix]
B --> B1[正しく分類できた割合<br/>最も基本的な指標]
C --> C1[Positiveと予測したうち<br/>実際にPositiveだった割合]
D --> D1[実際のPositiveのうち<br/>Positiveと予測できた割合]
E --> E1[適合率と再現率の<br/>調和平均]
F --> F1[予測と実際の結果を<br/>2×2の表で表現]
style A fill:#e6ccff
style B fill:#ccffcc
style C fill:#ffffcc
style D fill:#ffcccc
style E fill:#e6f3ff
style F fill:#cceeff
正解率(Accuracy)¶
正解率 は、全体のうち正しく分類できた割合です。
from sklearn.metrics import accuracy_score
accuracy = accuracy_score(y_test, y_pred)
print(f"正解率: {accuracy:.2%}")
混同行列(Confusion Matrix)¶
混同行列 は、予測結果と実際の結果を 2×2 の表で表現したものです。
| 予測: 0(Negative) | 予測: 1(Positive) | |
|---|---|---|
| 実際: 0(Negative) | TN(真陰性) | FP(偽陽性) |
| 実際: 1(Positive) | FN(偽陰性) | TP(真陽性) |
- TP(True Positive): 正しく Positive と予測
- TN(True Negative): 正しく Negative と予測
- FP(False Positive): 誤って Positive と予測(第一種過誤)
- FN(False Negative): 誤って Negative と予測(第二種過誤)
from sklearn.metrics import confusion_matrix
import seaborn as sns
# 混同行列
cm = confusion_matrix(y_test, y_pred)
print("混同行列:")
print(cm)
モデルの性能について
上記の混同行列を見ると、すべてのデータがDinner(0列目)と予測されており、Lunch(1列目)と予測されたものが1つもありません(すべて0)。これは、モデルが「常にDinnerと予測する」という単純な戦略を学習してしまった状態です。
なぜこのような結果になったのか?
- 特徴量が不足:
tip(チップ)だけでは時間帯を予測するのに十分な情報がない - データの偏り: Dinnerのデータ数がLunchより多い(176件 vs 61件)
改善するにはどうすればよいか?
- 特徴量を増やす:
total_bill(合計金額)、size(人数)なども使う - カテゴリ変数を活用:
sex(性別)、smoker(喫煙者)、day(曜日)を数値化するpd.get_dummies()を使ってダミー変数化(One-Hot Encoding)
例: ダミー変数化
# カテゴリ変数をダミー変数化
X = pd.get_dummies(tips[['total_bill', 'tip', 'sex', 'smoker', 'day']], drop_first=True)
このように、特徴量エンジニアリング(特徴量の選択・加工)は機械学習で非常に重要です。
適合率(Precision)と再現率(Recall)¶
適合率(Precision):
「Positive と予測したうち、実際に Positive だった割合」
再現率(Recall):
「実際の Positive のうち、Positive と予測できた割合」
from sklearn.metrics import precision_score, recall_score, f1_score
# pos_label で「Positive」とみなすクラスを指定(文字列ラベルの場合は必須)
precision = precision_score(y_test, y_pred, pos_label='Lunch')
recall = recall_score(y_test, y_pred, pos_label='Lunch')
f1 = f1_score(y_test, y_pred, pos_label='Lunch')
print(f"適合率(Lunch): {precision:.2%}")
print(f"再現率(Lunch): {recall:.2%}")
print(f"F1スコア(Lunch): {f1:.2%}")
適合率と再現率のトレードオフ
適合率を重視する場合(偽陽性を減らしたい):
- スパムメール判定(普通のメールをスパムと判定するのを避けたい)
- 広告配信(興味のない人に広告を出すのを避けたい)
再現率を重視する場合(偽陰性を減らしたい):
- 病気の診断(病気を見逃さないようにしたい)
- 不正取引の検出(不正を見逃さないようにしたい)
通常、適合率と再現率はトレードオフの関係にあります。
F1 スコア¶
F1 スコア は、適合率と再現率の調和平均です。
適合率と再現率のバランスを取った指標で、両方を重視したい場合に使います。
6.2.4 多値分類への拡張¶
ロジスティック回帰は、多値分類にも対応できます。scikit-learn の LogisticRegression はデフォルトで多値分類をサポートしています。
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, classification_report
import seaborn as sns
# アヤメデータセットの読み込み
iris = sns.load_dataset('iris')
# 特徴量とラベルの分離
X = iris[['sepal_length', 'sepal_width']].values
y = iris['species'].values
# データ分割
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
# モデルの学習
model = LogisticRegression(max_iter=200)
model.fit(X_train, y_train)
# 予測
y_pred = model.predict(X_test)
# 精度の計算
accuracy = accuracy_score(y_test, y_pred)
print(f"精度: {accuracy:.2%}")
# 詳細なレポート
print("\n分類レポート:")
print(classification_report(y_test, y_pred))
精度: 90.00%
分類レポート:
precision recall f1-score support
setosa 1.00 1.00 1.00 10
versicolor 0.88 0.78 0.82 9
virginica 0.83 0.91 0.87 11
accuracy 0.90 30
macro avg 0.90 0.90 0.90 30
weighted avg 0.90 0.90 0.90 30
6.3 決定木¶
6.3.1 決定木とは¶
決定木(Decision Tree) は、データを「木構造」で分類するアルゴリズムです。if-then ルールの集まりとして表現され、人間が理解しやすいのが特徴です。
graph TB
A[花弁の長さ ≤ 2.5cm?] -->|Yes| B[Setosa]
A -->|No| C[花弁の幅 ≤ 1.7cm?]
C -->|Yes| D[Versicolor]
C -->|No| E[Virginica]
style A fill:#e6ccff
style B fill:#ccffcc
style C fill:#ffffcc
style D fill:#ffcccc
style E fill:#e6f3ff
決定木の特徴:
- 解釈性が高い: ルールが明確で説明しやすい
- 非線形: 複雑な境界を表現できる
- 前処理不要: 標準化やダミー変数化が不要
- 過学習しやすい: 深くしすぎると訓練データに過度に適合
6.3.2 決定木の仕組み¶
決定木は、データを「分割」していくことで分類を行います。
情報利得(Information Gain) や ジニ不純度(Gini Impurity) という指標を使って、最も効果的な分割方法を選びます。
ジニ不純度
ジニ不純度は、データの「混ざり具合」を表す指標です。
- 完全に1つのクラスだけ → ジニ不純度 = 0(純粋)
- クラスが均等に混ざっている → ジニ不純度が大きい(不純)
決定木は、ジニ不純度が小さくなるように分割を繰り返します。
6.3.3 決定木の実装¶
決定木を実装するには、sklearn.tree.DecisionTreeClassifier() クラスを使用します。
import numpy as np
import matplotlib.pyplot as plt
from sklearn.tree import DecisionTreeClassifier, plot_tree
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, classification_report
import seaborn as sns
# アヤメデータセットの読み込み
iris = sns.load_dataset('iris')
# 特徴量とラベルの分離
X = iris[['petal_length', 'petal_width']].values
y = iris['species'].values
# データ分割
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
# 決定木モデルの学習(最大深さ3)
model = DecisionTreeClassifier(max_depth=3, random_state=42)
model.fit(X_train, y_train)
# 予測
y_pred = model.predict(X_test)
# 精度の計算
accuracy = accuracy_score(y_test, y_pred)
print(f"精度: {accuracy:.2%}")
# 詳細なレポート
print("\n分類レポート:")
print(classification_report(y_test, y_pred))
精度: 100.00%
分類レポート:
precision recall f1-score support
setosa 1.00 1.00 1.00 10
versicolor 1.00 1.00 1.00 9
virginica 1.00 1.00 1.00 11
accuracy 1.00 30
macro avg 1.00 1.00 1.00 30
weighted avg 1.00 1.00 1.00 30
分類結果の可視化例
6.3.4 決定木のハイパーパラメータ¶
決定木の性能を調整するための主なハイパーパラメータ:
max_depth: 木の最大深さ
- 小さい → シンプルなモデル(未学習のリスク)
- 大きい → 複雑なモデル(過学習のリスク)
min_samples_split: 分割に必要な最小サンプル数
- 大きい → 分割が少なくなる(シンプル)
- 小さい → より細かく分割(複雑)
決定木の過学習
max_depth=None(深さ制限なし)にすると、訓練データに完全に適合してしまい、テストデータでの性能が悪化します(過学習)。
適切な深さは、交差検証などで決定します。
6.4 ランダムフォレスト¶
6.4.1 ランダムフォレストとは¶
ランダムフォレスト(Random Forest) は、複数の決定木を組み合わせた アンサンブル学習(集団学習) の一種です。
graph TB
A[訓練データ] --> B1[決定木 1]
A --> B2[決定木 2]
A --> B3[決定木 3]
A --> B4[...]
A --> B5[決定木 N]
B1 --> C[投票]
B2 --> C
B3 --> C
B4 --> C
B5 --> C
C --> D[最終予測]
style A fill:#e6ccff
style B1 fill:#ccffcc
style B2 fill:#ccffcc
style B3 fill:#ccffcc
style B4 fill:#ccffcc
style B5 fill:#ccffcc
style C fill:#ffffcc
style D fill:#ffcccc
ランダムフォレストの特徴
- 高精度: 単一の決定木より高い精度
- 過学習に強い: 複数の木の平均を取るため
- 特徴量の重要度: どの特徴量が重要かが分かる
- 並列化が可能: 各木を独立に学習できる
6.4.2 ランダムフォレストの仕組み¶
ランダムフォレストは以下の手順で動作します:
- ブートストラップサンプリング: 訓練データからランダムにサンプリング(重複あり)
- ランダムな特徴量選択: 各分割でランダムに特徴量のサブセットを選択
- 複数の決定木を学習: それぞれ異なるデータ・特徴量で学習
- 投票で決定: 全ての木の予測結果を多数決で決定
なぜランダム性を入れるのか?
- 多様性: 各決定木が異なるパターンを学習
- 汎化性能: 特定のデータへの過度な適合を防ぐ
- ロバスト性: 一部の木が間違えても、他の木が補える
6.4.3 ランダムフォレストの実装¶
ランダムフォレストを実装するには、sklearn.ensemble.RandomForestClassifier() クラスを使用します。
import numpy as np
import matplotlib.pyplot as plt
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, classification_report
import seaborn as sns
# アヤメデータセットの読み込み
iris = sns.load_dataset('iris')
# 特徴量とラベルの分離
X = iris[['petal_length', 'petal_width']].values
y = iris['species'].values
# データ分割
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
# ランダムフォレストモデルの学習
model = RandomForestClassifier(n_estimators=100, max_depth=3, random_state=42)
model.fit(X_train, y_train)
# 予測
y_pred = model.predict(X_test)
# 精度の計算
accuracy = accuracy_score(y_test, y_pred)
print(f"精度: {accuracy:.2%}")
# 詳細なレポート
print("\n分類レポート:")
print(classification_report(y_test, y_pred))
精度: 100.00%
分類レポート:
precision recall f1-score support
setosa 1.00 1.00 1.00 10
versicolor 1.00 1.00 1.00 9
virginica 1.00 1.00 1.00 11
accuracy 1.00 30
macro avg 1.00 1.00 1.00 30
weighted avg 1.00 1.00 1.00 30
分類結果の可視化例
6.4.4 特徴量の重要度¶
ランダムフォレストでは、各特徴量がどれだけ重要かを定量的に評価できます。
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
import seaborn as sns
# アヤメデータセットの読み込み(全特徴量使用)
iris = sns.load_dataset('iris')
X = iris.drop('species', axis=1)
y = iris['species']
# データ分割
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
# ランダムフォレストの学習
model = RandomForestClassifier(n_estimators=100, random_state=42)
model.fit(X_train, y_train)
# 特徴量の重要度
importances = model.feature_importances_
feature_names = X.columns
# DataFrameに整理
importance_df = pd.DataFrame({
'特徴量': feature_names,
'重要度': importances
}).sort_values('重要度', ascending=False)
print("特徴量の重要度:")
print(importance_df)
# 可視化
plt.figure(figsize=(8, 5))
plt.barh(importance_df['特徴量'], importance_df['重要度'])
plt.xlabel('重要度')
plt.title('特徴量の重要度')
plt.gca().invert_yaxis()
plt.show()
特徴量の重要度:
特徴量 重要度
2 petal_length 0.439994
3 petal_width 0.421522
0 sepal_length 0.108098
1 sepal_width 0.030387
特徴量の重要度の活用
- 特徴量選択: 重要度の低い特徴量を削除してモデルを簡略化
- データ収集の優先順位: 重要な特徴量を優先的に収集
- ビジネス理解: どの要因が重要かを理解
6.4.5 ランダムフォレストのハイパーパラメータ¶
n_estimators: 木の数
- 多い → 精度向上、計算時間増加
- 一般的に 100〜500 程度
max_depth: 各木の最大深さ
- 決定木と同様に過学習を制御
max_features: 分割時に考慮する特徴量の数
'sqrt': √(特徴量数)(分類のデフォルト)'log2': log₂(特徴量数)- 数値: 具体的な数を指定
6.5 モデルの比較¶
各手法の特徴まとめ
ロジスティック回帰:
- シンプルで解釈しやすい
- 線形な境界しか表現できない
- 計算が高速
- 特徴量が少ない場合に有効
決定木:
- 非線形な境界を表現できる
- 解釈性が非常に高い
- 過学習しやすい
- ルールベースの説明が必要な場合に有効
ランダムフォレスト:
- 高精度
- 過学習に強い
- 解釈性はやや低い
- 実務で最もよく使われる
6.6 演習問題¶
演習 6-1: ペンギンデータセットでロジスティック回帰¶
演習 6-1
ペンギンデータセット(penguins)を使って、ロジスティック回帰で種類を分類してください。
タスク:
- データの読み込みと欠損値の削除
- 特徴量として全ての数値列(bill_length_mm, bill_depth_mm, flipper_length_mm, body_mass_g)を使用
- データを訓練データとテストデータに分割(8:2)
- ロジスティック回帰モデルを学習
- 精度、分類レポート、混合行列を出力
演習 6-2: ペンギンデータセットで決定木¶
演習 6-2
ペンギンデータセット(penguins)を使って、決定木で種類を分類してください。
タスク:
- データの読み込みと欠損値の削除
- 特徴量として全ての数値列を使用
- データを訓練データとテストデータに分割(8:2)
- 適切な
max_depthで決定木を学習 - 精度、分類レポート、混合行列を出力
6.7 課題 6: タイタニックデータセットでの生存予測¶
課題 6
タイタニックデータセット(titanic)を使って、乗客の生存を予測する分類モデルを実装してください。
タスク:
- データの読み込みと前処理
- 必要な列の抽出(survived, pclass, sex, age, fare など)
- 欠損値の処理(dropna()またはfillna())
- カテゴリ変数のダミー変数化(
pd.get_dummies())
- データ分割(訓練:テスト = 8:2)
- 分類モデルを学習(一つ選択)
- モデルの精度、分類レポート、混同行列を出力
※ 加点要素:複数のモデルやハイパーパラメータによる精度比較
提出物:
- Word ファイルで作成し、PDF 形式で出力して提出(学生番号_氏名_6.pdf)
- 問題文・ソースコード・結果・考察を PDF 内に含めること(参考:
機械学習_レポートサンプル.docx)
提出期限: 2025年11月12日(水)23:59
提出先: manaba
ヒント
データの前処理例:
titanic データセットについて
今回の課題では、タイタニック号の沈没事故に遭遇した乗客に関する情報を含む、titanic データセットを使用します。このデータセットには、乗客の年齢、性別、乗客クラス、生存状況などの情報が含まれており、データ分析や可視化、機械学習の練習用として頻繁に使用されます。
CSV データ https://github.com/mwaskom/seaborn-data/blob/master/titanic.csv
データの概要
survived: 生存状況 (0= 死亡,1= 生存)pclass: 乗客クラス (1= 1等船室,2= 2等船室,3= 3等船室)sex: 性別 (maleorfemale)age: 年齢sibsp: 同乗している兄弟姉妹 (sibling) または配偶者 (spouse) の数parch: 同乗している親 (parent) または子供 (children) の数fare: 乗船料金embarked: 乗船した港 (C= Cherbourg,Q= Queenstown,S= Southampton)class: 客室クラス (FirstorSecondorThird) ※pclassの文字列版who: 人物 (manorwomanorchild) ※ 性別と年齢を組み合わせた分類adult_male: 成人男性フラグ (True/False)deck: 客室のデッキ (A~G)embark_town: 乗船した都市(CherbourgorQueenstownorSouthampton)※embarkedの都市名版alive: 生存状況 (yesorno) ※survivedの文字列版alone: 単独乗船フラグ (True/False) ※sibsp + parch == 0のときTrue
6.8 まとめ¶
本章では、機械学習における基本的な分類モデルについて学びました。
第 6 回のまとめ
分類問題の基礎
- 回帰は数値予測、分類はカテゴリ予測
- 2値分類(2クラス)と多値分類(3クラス以上)
- 実務での応用範囲が広い
ロジスティック回帰
- シグモイド関数で確率を出力
- 線形な決定境界
- シンプルで解釈しやすい
- 多値分類にも対応可能
決定木
- if-then ルールで分類
- 非線形な境界を表現可能
- 解釈性が非常に高い
- 過学習しやすいので深さの調整が重要
ランダムフォレスト
- 複数の決定木を組み合わせたアンサンブル学習
- 高精度で過学習に強い
- 特徴量の重要度が分かる
- 実務で最もよく使われる手法の一つ
評価指標
- 正解率(Accuracy): 基本的な指標
- 混同行列(Confusion Matrix): 予測の詳細を把握
- 適合率(Precision): 偽陽性を重視
- 再現率(Recall): 偽陰性を重視
- F1スコア: 適合率と再現率のバランス
モデルの選び方
- シンプルで解釈重視 → ロジスティック回帰、決定木
- 精度重視 → ランダムフォレスト
- ルールベースの説明が必要 → 決定木
- 実務での汎用性 → ランダムフォレスト


