STEP 25:モデル選択の戦略

🎯 STEP 25: モデル選択の戦略

問題に最適なアルゴリズムを選び、複数モデルを組み合わせる

📋 このステップで学ぶこと

  • No Free Lunch定理とは
  • アルゴリズム選択の考え方
  • 分類問題のアルゴリズム比較
  • 回帰問題のアルゴリズム比較
  • 投票(Voting)による組み合わせ
  • スタッキング(Stacking)による組み合わせ

演習問題: 5問

🎯 1. No Free Lunch定理

機械学習を始めると「どのアルゴリズムが一番良いの?」という疑問が浮かびます。実は、この問いに対する答えは「万能なアルゴリズムは存在しない」です。

📊 No Free Lunch定理(ノーフリーランチ定理)

「全ての問題に対して最良のアルゴリズムは存在しない」

あるアルゴリズムがある問題で優れていても、別の問題では劣ることがある。
つまり、問題ごとに最適なアルゴリズムを選ぶ必要がある。

では、どうやって最適なアルゴリズムを選べばよいのでしょうか?それには、各アルゴリズムの特徴と得意分野を理解することが重要です。

アルゴリズム選択の考慮点

【アルゴリズム選択で考慮すべき5つのポイント】 1. データの量 – 少ない(〜1000件): シンプルなモデル(ロジスティック回帰、決定木) – 多い(1万件〜): 複雑なモデルも使える(ランダムフォレスト、XGBoost) 2. データの特性 – 線形関係: 線形回帰、ロジスティック回帰 – 非線形関係: 決定木系、SVM(RBFカーネル)、ニューラルネット 3. 解釈性の要求 – 高い(説明が必要): 決定木、ロジスティック回帰 – 低い(精度優先): XGBoost、ニューラルネット 4. 計算リソース – 限られている: シンプルなモデル、特徴量を減らす – 十分ある: アンサンブル、ハイパーパラメータチューニング 5. 予測速度の要求 – リアルタイム必要: シンプルなモデル – バッチ処理でOK: 複雑なモデルも可

📊 2. 分類アルゴリズムの比較

まず、主要な分類アルゴリズムの特徴を整理し、実際にデータで比較してみましょう。

アルゴリズム 得意なこと 苦手なこと 解釈性
ロジスティック回帰 線形分離可能なデータ、確率出力 非線形な境界 ◎ 高い
決定木 解釈しやすい、前処理不要 過学習しやすい ◎ 高い
ランダムフォレスト 安定性、特徴量重要度 計算コスト、メモリ ○ 中程度
XGBoost/LightGBM 高精度、欠損値対応 過学習リスク、チューニング △ 低め
SVM 高次元、非線形境界 大規模データ、確率出力 × 低い
KNN シンプル、非線形対応 高次元、計算速度 △ 低め

複数のアルゴリズムを比較するコード

複数のモデルを同じデータで比較する手順:
  1. 比較したいモデルを辞書にまとめる
  2. 各モデルに対して交差検証を実行
  3. 結果を比較して最適なモデルを選択
# 必要なライブラリをインポート import numpy as np from sklearn.datasets import load_breast_cancer # 乳がんデータセット from sklearn.model_selection import cross_val_score, StratifiedKFold # 比較する分類アルゴリズムをインポート from sklearn.linear_model import LogisticRegression # ロジスティック回帰 from sklearn.tree import DecisionTreeClassifier # 決定木 from sklearn.ensemble import RandomForestClassifier # ランダムフォレスト from sklearn.svm import SVC # サポートベクターマシン from sklearn.neighbors import KNeighborsClassifier # K近傍法 from sklearn.preprocessing import StandardScaler # 標準化 from sklearn.pipeline import Pipeline # パイプライン # データを読み込む # 乳がんの診断データ(569サンプル、30特徴量、2クラス) cancer = load_breast_cancer() X, y = cancer.data, cancer.target print(f”データサイズ: {X.shape}”) print(f”クラス分布: {np.bincount(y)}”) # [212 357] = 悪性212, 良性357
モデルを辞書で定義する理由:

forループで順番に処理できるようになり、コードがシンプルになります。
Pipelineを使うと、前処理(スケーリング)とモデルをセットで管理できます。

# 比較するモデルを辞書で定義 # SVMやKNNはスケーリングが必要なのでPipelineを使用 models = { ‘ロジスティック回帰’: Pipeline([ (‘scaler’, StandardScaler()), # 標準化 (‘model’, LogisticRegression(max_iter=1000)) # モデル ]), ‘決定木’: DecisionTreeClassifier( max_depth=5, # 過学習を防ぐため深さを制限 random_state=42 # 再現性のため ), ‘ランダムフォレスト’: RandomForestClassifier( n_estimators=100, # 100本の木を使用 max_depth=10, # 各木の深さを制限 random_state=42 ), ‘SVM’: Pipeline([ (‘scaler’, StandardScaler()), # SVMはスケーリングが重要 (‘model’, SVC(kernel=’rbf’, random_state=42)) # RBFカーネル ]), ‘KNN’: Pipeline([ (‘scaler’, StandardScaler()), # KNNもスケーリングが重要 (‘model’, KNeighborsClassifier(n_neighbors=5)) # 5近傍 ]) }
# 交差検証の設定 # StratifiedKFold: クラス比率を維持した分割(分類問題で推奨) cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42) # 各モデルを評価して比較 print(“=”*60) print(“分類アルゴリズムの比較(5-Fold Stratified CV)”) print(“=”*60) results = {} # 結果を保存する辞書 for name, model in models.items(): # cross_val_score: 交差検証でスコアを計算 # scoring=’accuracy’: 正解率で評価 scores = cross_val_score(model, X, y, cv=cv, scoring=’accuracy’) # 結果を保存 results[name] = { ‘mean’: scores.mean(), # 平均スコア ‘std’: scores.std() # 標準偏差 } # 結果を表示 print(f”\n{name}:”) print(f” 各Foldのスコア: {scores.round(4)}”) print(f” 平均: {scores.mean():.4f} (±{scores.std():.4f})”)
============================================================ 分類アルゴリズムの比較(5-Fold Stratified CV) ============================================================ ロジスティック回帰: 各Foldのスコア: [0.9649 0.9737 0.9649 0.9912 0.9646] 平均: 0.9719 (±0.0102) 決定木: 各Foldのスコア: [0.9211 0.9386 0.9386 0.9558 0.9292] 平均: 0.9366 (±0.0118) ランダムフォレスト: 各Foldのスコア: [0.9561 0.9737 0.9649 0.9823 0.9558] 平均: 0.9666 (±0.0102) SVM: 各Foldのスコア: [0.9737 0.9825 0.9649 0.9912 0.9735] 平均: 0.9772 (±0.0092) KNN: 各Foldのスコア: [0.9474 0.9649 0.9561 0.9735 0.9381] 平均: 0.9560 (±0.0126)
✅ 結果の解釈
  • SVMが最高スコア(97.72%)で標準偏差も最小(安定)
  • ロジスティック回帰も高スコア(97.19%)で解釈性が高い
  • 決定木は最も低い(93.66%)が、解釈性は最高
  • このデータではSVMロジスティック回帰が適切

📈 3. 回帰アルゴリズムの比較

回帰問題(連続値の予測)でも同様に複数のアルゴリズムを比較してみましょう。

# 回帰アルゴリズムの比較 from sklearn.datasets import fetch_california_housing # 住宅価格データ from sklearn.linear_model import LinearRegression, Ridge, Lasso from sklearn.tree import DecisionTreeRegressor from sklearn.ensemble import RandomForestRegressor from sklearn.svm import SVR from sklearn.model_selection import cross_val_score # データを読み込む housing = fetch_california_housing() X_reg, y_reg = housing.data, housing.target print(f”データサイズ: {X_reg.shape}”) print(f”目的変数の範囲: {y_reg.min():.2f} 〜 {y_reg.max():.2f}”)
# 比較する回帰モデルを定義 reg_models = { ‘線形回帰’: Pipeline([ (‘scaler’, StandardScaler()), (‘model’, LinearRegression()) ]), ‘Ridge回帰’: Pipeline([ (‘scaler’, StandardScaler()), (‘model’, Ridge(alpha=1.0)) # L2正則化 ]), ‘Lasso回帰’: Pipeline([ (‘scaler’, StandardScaler()), (‘model’, Lasso(alpha=0.01)) # L1正則化 ]), ‘決定木’: DecisionTreeRegressor( max_depth=10, random_state=42 ), ‘ランダムフォレスト’: RandomForestRegressor( n_estimators=100, max_depth=10, random_state=42, n_jobs=-1 # 並列処理 ) } # 各モデルを評価 print(“=”*60) print(“回帰アルゴリズムの比較(5-Fold CV)”) print(“=”*60) for name, model in reg_models.items(): # 回帰では neg_root_mean_squared_error を使用 # (負の値なので、実際のRMSEは符号を反転) scores = cross_val_score( model, X_reg, y_reg, cv=5, scoring=’neg_root_mean_squared_error’ ) rmse = -scores.mean() # 負を反転してRMSEに std = scores.std() print(f”\n{name}:”) print(f” RMSE: {rmse:.4f} (±{std:.4f})”)
============================================================ 回帰アルゴリズムの比較(5-Fold CV) ============================================================ 線形回帰: RMSE: 0.7456 (±0.0234) Ridge回帰: RMSE: 0.7451 (±0.0231) Lasso回帰: RMSE: 0.7523 (±0.0245) 決定木: RMSE: 0.7234 (±0.0312) ランダムフォレスト: RMSE: 0.5234 (±0.0187)
💡 回帰の評価指標について

scoring='neg_root_mean_squared_error'は「負のRMSE」を返します。
scikit-learnでは「スコアは大きいほど良い」というルールがあるため、
誤差(小さいほど良い)に負号をつけています。

実際のRMSEを得るには-scores.mean()で符号を反転します。

🗳️ 4. 投票(Voting)によるアンサンブル

複数のモデルの予測を多数決で組み合わせる方法です。異なる種類のモデルを組み合わせると、個々のモデルの弱点を補い合えます。

📊 Votingの2種類
  • Hard Voting:各モデルの予測クラスの多数決
  • Soft Voting:各モデルの予測確率を平均してクラスを決定(推奨)

VotingClassifierの使い方

VotingClassifierの主な引数:
  • estimators:組み合わせるモデルのリスト((名前, モデル)のタプル)
  • voting='soft':予測確率を平均(’hard’だと多数決)
  • Soft Votingには確率を出力できるモデルが必要(SVMはprobability=True
# VotingClassifierの使い方 from sklearn.ensemble import VotingClassifier # 組み合わせるモデルを定義 # それぞれ異なるタイプのモデルを選ぶと効果的 estimators = [ # (名前, モデル) のタプルで指定 (‘lr’, LogisticRegression(max_iter=1000)), # 線形モデル (‘rf’, RandomForestClassifier(n_estimators=100, random_state=42)), # 木ベース (‘svm’, SVC(probability=True, random_state=42)) # カーネルベース # probability=True: Soft Votingに必要(確率を出力するため) ] # VotingClassifierを作成 voting_clf = VotingClassifier( estimators=estimators, # 組み合わせるモデル voting=’soft’ # 予測確率を平均(推奨) )
# 個別モデルとVotingの性能を比較 # データを準備(乳がんデータ) X_scaled = StandardScaler().fit_transform(X) # スケーリング print(“=”*60) print(“個別モデル vs Voting の比較”) print(“=”*60) # 個別モデルの評価 for name, model in estimators: scores = cross_val_score(model, X_scaled, y, cv=5) print(f”{name}: {scores.mean():.4f} (±{scores.std():.4f})”) # Votingの評価 scores_voting = cross_val_score(voting_clf, X_scaled, y, cv=5) print(f”\nVoting (Soft): {scores_voting.mean():.4f} (±{scores_voting.std():.4f})”)
============================================================ 個別モデル vs Voting の比較 ============================================================ lr: 0.9719 (±0.0102) rf: 0.9666 (±0.0102) svm: 0.9772 (±0.0092) Voting (Soft): 0.9789 (±0.0087)
✅ Votingの効果

個別モデルの最高スコアは97.72%(SVM)でしたが、
Votingでは97.89%に向上し、標準偏差も最小になりました。
異なるモデルを組み合わせることで、安定性と精度が向上しています。

📚 5. スタッキング(Stacking)

スタッキングは、複数のモデルの予測を別のモデル(メタモデル)で統合する高度なアンサンブル手法です。

📊 スタッキングの仕組み

第1層(ベースモデル):複数のモデルが予測を出す
第2層(メタモデル):ベースモデルの予測を特徴量として、最終予測を出す

Votingとの違い:単純な平均/多数決ではなく、どのモデルをどれだけ信頼するかを学習する

【スタッキングのイメージ】 入力データ X │ ┌────────┼────────┐ ↓ ↓ ↓ モデル1 モデル2 モデル3 ← 第1層(ベースモデル) │ │ │ ↓ ↓ ↓ 予測1 予測2 予測3 │ │ │ └────────┼────────┘ ↓ メタモデル ← 第2層(予測を統合) │ ↓ 最終予測

StackingClassifierの使い方

StackingClassifierの主な引数:
  • estimators:ベースモデル(第1層)のリスト
  • final_estimator:メタモデル(第2層)
  • cv=5:ベースモデルの予測を作る際のCV(データリーク防止)
  • passthrough=True:元の特徴量もメタモデルに渡す(オプション)
# StackingClassifierの使い方 from sklearn.ensemble import StackingClassifier # ベースモデル(第1層)を定義 base_estimators = [ (‘lr’, LogisticRegression(max_iter=1000)), (‘rf’, RandomForestClassifier(n_estimators=100, random_state=42)), (‘svm’, SVC(probability=True, random_state=42)) ] # メタモデル(第2層)を定義 # ベースモデルの予測を入力として、最終予測を出す # シンプルなモデル(ロジスティック回帰など)が推奨 meta_model = LogisticRegression(max_iter=1000) # StackingClassifierを作成 stacking_clf = StackingClassifier( estimators=base_estimators, # ベースモデル final_estimator=meta_model, # メタモデル cv=5, # ベースモデルの予測作成時のCV passthrough=False # 元の特徴量を使わない(Trueにすると使う) ) # 評価 scores_stacking = cross_val_score(stacking_clf, X_scaled, y, cv=5) print(“=”*60) print(“Stacking vs Voting vs 個別モデル”) print(“=”*60) print(f”最良の個別モデル(SVM): 0.9772 (±0.0092)”) print(f”Voting (Soft): {scores_voting.mean():.4f} (±{scores_voting.std():.4f})”) print(f”Stacking: {scores_stacking.mean():.4f} (±{scores_stacking.std():.4f})”)
============================================================ Stacking vs Voting vs 個別モデル ============================================================ 最良の個別モデル(SVM): 0.9772 (±0.0092) Voting (Soft): 0.9789 (±0.0087) Stacking: 0.9807 (±0.0079)
💡 VotingとStackingの使い分け
  • Voting:シンプル、解釈しやすい、計算が速い
  • Stacking:より高精度の可能性、計算コストが高い
  • まずVotingを試し、さらなる精度向上が必要ならStackingを検討

🎯 6. 実践的なモデル選択フロー

【モデル選択の実践フロー】 ステップ1: ベースラインを作る └─ シンプルなモデル(ロジスティック回帰、決定木)で基準を設定 ステップ2: 複数のアルゴリズムを比較 └─ 交差検証で公平に比較 └─ 最低3〜5種類は試す ステップ3: 上位モデルをチューニング └─ ハイパーパラメータを最適化 └─ 上位2〜3モデルに集中 ステップ4: アンサンブルを検討 └─ 異なるタイプのモデルを組み合わせ └─ VotingまたはStacking ステップ5: 最終評価 └─ テストデータで最終確認 └─ 過学習していないか確認
# 実践的なモデル選択の完成コード import numpy as np from sklearn.datasets import load_breast_cancer from sklearn.model_selection import cross_val_score, StratifiedKFold from sklearn.preprocessing import StandardScaler from sklearn.pipeline import Pipeline from sklearn.linear_model import LogisticRegression from sklearn.tree import DecisionTreeClassifier from sklearn.ensemble import RandomForestClassifier, VotingClassifier from sklearn.svm import SVC from sklearn.neighbors import KNeighborsClassifier # データ準備 cancer = load_breast_cancer() X, y = cancer.data, cancer.target # 交差検証の設定 cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42) # 比較するモデル models = { ‘ロジスティック回帰’: Pipeline([(‘scaler’, StandardScaler()), (‘model’, LogisticRegression(max_iter=1000))]), ‘決定木’: DecisionTreeClassifier(max_depth=5, random_state=42), ‘ランダムフォレスト’: RandomForestClassifier(n_estimators=100, random_state=42), ‘SVM’: Pipeline([(‘scaler’, StandardScaler()), (‘model’, SVC(probability=True, random_state=42))]), ‘KNN’: Pipeline([(‘scaler’, StandardScaler()), (‘model’, KNeighborsClassifier(n_neighbors=5))]) } # 評価と結果保存 results = [] for name, model in models.items(): scores = cross_val_score(model, X, y, cv=cv, scoring=’accuracy’) results.append({‘name’: name, ‘mean’: scores.mean(), ‘std’: scores.std()}) # 結果をスコア順にソート results_sorted = sorted(results, key=lambda x: x[‘mean’], reverse=True) print(“=”*60) print(“モデル比較結果(スコア順)”) print(“=”*60) for i, r in enumerate(results_sorted, 1): print(f”{i}. {r[‘name’]}: {r[‘mean’]:.4f} (±{r[‘std’]:.4f})”)

📝 練習問題

問題1 やさしい

No Free Lunch定理

No Free Lunch定理の意味として正しいものはどれですか?

  • A. 機械学習は無料で使える
  • B. 全ての問題に最良のアルゴリズムは存在しない
  • C. ランチを食べながら機械学習を学ぶべき
正解:B

「全ての問題に対して最良のアルゴリズムは存在しない」という意味です。問題ごとに最適なアルゴリズムを選ぶ必要があります。

問題2 ふつう

Soft VotingとHard Voting

Soft VotingがHard Votingより推奨される理由は何ですか?

理由:予測の確信度を考慮できるから

Hard Votingは単純な多数決ですが、Soft Votingは各モデルの予測確率を平均するため、「どれだけ確信を持って予測しているか」を考慮できます。

問題3 むずかしい

VotingClassifierの実装

ロジスティック回帰、決定木、SVMを組み合わせたVotingClassifierを作成してください。

from sklearn.ensemble import VotingClassifier from sklearn.linear_model import LogisticRegression from sklearn.tree import DecisionTreeClassifier from sklearn.svm import SVC # 組み合わせるモデル estimators = [ (‘lr’, LogisticRegression(max_iter=1000)), (‘dt’, DecisionTreeClassifier(max_depth=5)), (‘svm’, SVC(probability=True)) # Soft Voting用 ] # VotingClassifierを作成 voting_clf = VotingClassifier( estimators=estimators, voting=’soft’ ) # 訓練と予測 voting_clf.fit(X_train, y_train) predictions = voting_clf.predict(X_test)

📝 STEP 25 のまとめ

✅ このステップで学んだこと
  • No Free Lunch定理:万能なアルゴリズムは存在しない
  • アルゴリズム選択:データ量、特性、解釈性、計算リソースを考慮
  • 複数モデルの比較:交差検証で公平に評価
  • Voting:複数モデルの予測を多数決/平均で統合
  • Stacking:メタモデルで予測を学習して統合
🚀 次のステップへ

次のSTEP 26では、特徴量の変換とエンコーディングを学びます。数値データのスケーリングやカテゴリカルデータの変換方法を習得しましょう!

❓ よくある質問

Q1. 最初にどのモデルを試すべき?
分類ならロジスティック回帰、回帰ならRidge回帰をベースラインとして推奨します。シンプルで速く、基準として使いやすいです。
Q2. アンサンブルに何モデル組み合わせるべき?
一般的に3〜5モデルが推奨されます。多すぎると計算コストが増え、改善効果も小さくなります。また、異なるタイプのモデルを組み合わせることが重要です。
Q3. 解釈性と精度、どちらを優先すべき?
ビジネス要件次第です。医療診断やローン審査など説明が必要な場合は解釈性を優先。広告のクリック予測など精度が最優先の場合は複雑なモデルを選択します。
📝

学習メモ

機械学習入門 - Step 25

📋 過去のメモ一覧
#artnasekai #学習メモ
LINE