Velvet Theory AIとデータの話を、やわらかく、筋道立てて。

機械学習の全体地図(3)作って確かめる手順

前処理、データ分割と交差検証、過学習と未学習、損失関数と最適化、ハイパーパラメータの探し方まで、どの手法にも共通する作り方と確かめ方をまとめます。過学習や学習率をスライダーで試せるデモ付き。

連載 機械学習の全体地図 第3回/全8回
  1. 第1回全体像と「学び方」
  2. 第2回タスクとモデル
  3. 第3回作って確かめる手順
  4. 第4回評価指標と落とし穴
  5. 第5回深層学習とLLM
  6. 第6回運用と責任あるAI
  7. 第7回Pythonで書く
  8. 第8回通しチュートリアル:解約予測

④ 手順:どう作り、どう確かめるか

どの手法でも流れは共通です。評価で満足できなければ前の段階に戻ります。Pythonでの書き方は「Pythonで書く」の基本の型を参照してください。

  1. 課題を定義する業務の目的を、①学び方と②タスクの言葉に置き換え、評価指標と「超えるべき基準(単純な方法の成績)」を決める
  2. データを集める予測に使う時点で本当に手に入るデータかを確認する
  3. データを分割する最初にテスト用を取り分け、残りを学習用と検証用に分ける。以降の観察・前処理は学習用データで行う
  4. データを観察する(EDA)分布、欠損、外れ値、クラスの偏り、変数同士の関係を見る
  5. 前処理する下の表を参照。平均値など前処理に使う値は学習用データだけで計算し、検証・テストにはその値を当てはめる
  6. 特徴量を作る業務知識から予測に効く変数を作る(比率、日付の曜日化、集計値など)。効かない変数を減らす特徴量選択もここで行う
  7. 学習する損失関数(予測の外れ具合を表す数値)が小さくなるようにパラメータを調整する
  8. 評価する検証用データで指標を計算し、誤りの傾向を分析する。特徴量重要度やSHAPで予測の根拠も確認する
  9. チューニングするハイパーパラメータ(木の深さなど、人が決める設定)や特徴量を改善し、最後にテスト用データで1回だけ確認
  10. 本番に載せる他のシステムから呼び出せる形(API)にする、毎晩まとめて予測する処理に組み込む、など
  11. 監視・再学習する本番データの分布の変化(ドリフト)で精度は落ちるため、定期的に確認し作り直す
強化学習の場合。固定のデータを分割する代わりに、環境の中で方策を実際に動かし、得られた報酬で評価します。

前処理の全パターン Preprocessing

課題手法注意点
欠損値行・列の削除/平均・中央値・最頻値で補完/モデルで補完/「欠損だった」フラグを追加欠損していること自体が情報になる場合がある
外れ値除去/上下限で切る(クリップ)/対数変換入力ミスか本物の極端値かを先に見極める
尺度の違い標準化 (x−平均)÷標準偏差/Min-Max正規化(学習データの範囲を0〜1にする)線形・距離・NN系には必要、決定木系には不要。Min-Maxでは、学習範囲外のテスト値は0〜1をはみ出す
カテゴリ変数One-hot(カテゴリごとに0/1の列を作る)/番号に置き換える(ラベルエンコーディング)/ターゲットエンコーディング(カテゴリを、そのカテゴリの正解の平均値に置き換える)/埋め込み(意味を反映した数値の並び=ベクトルに変換)番号化は大小関係を誤って持ち込むので主に木系向け。ターゲットエンコーディングはリーク(本来使えない正解の情報が混ざること)に注意(scikit-learnの TargetEncoder は fit_transform の中で交差検証して防ぐ)
テキストBag of Words(単語の出現回数)/TF-IDF(どの文書にも出る単語の重みを下げた出現頻度)/埋め込みベクトル日本語は、先に文を単語に区切る処理(形態素解析)が必要。scikit-learnの既定設定では1文字の語が捨てられる
画像・音声サイズ・長さの統一/画素値の正規化/データ拡張(回転・反転・ノイズ付加など)データ拡張は学習用データにだけ行う
データの品質重複の削除/誤ったラベルの修正同じデータが学習と検証の両方に入ると、評価が甘くなる
クラスの偏り多数派を減らす(アンダーサンプリング)/少数派を増やす(オーバーサンプリング。少数派の点の間に人工の点を作るSMOTEなど)/クラスの重み付け/判定の閾値調整サンプリングは学習用データにだけ行う

データ分割と検証の全パターン Cross-validation

学習検証テスト
学習 検証 テスト
ホールドアウト:1回だけ分ける
1回目2回目3回目4回目5回目
k分割交差検証(k=5):検証の担当を入れ替えて5回評価し、平均をとる
1回目2回目3回目時間
時系列分割:必ず過去で学び、その直後の期間で検証する
方法やり方使う場面
ホールドアウト学習/検証/テストに1回だけ分けるデータが多いとき
k分割交差検証k個に分け、1つずつ検証用にしてk回評価し平均。kをデータ件数にしたものを1個抜き交差検証(LOO)と呼ぶデータが少なめのとき
層化k分割各分割でクラスの比率を揃える分類、特に偏りがあるとき
時系列分割必ず過去で学び、未来で検証する時系列データ(シャッフル禁止)
グループk分割同じ人・同じ店のデータを学習と検証にまたがらせない1つの対象から複数行あるとき

過学習と未学習 Overfitting / Underfitting

未学習単純すぎて外れる
ちょうど良い傾向をとらえる
過学習点に合わせすぎ
ちょうど良い学習データの誤差検証データの誤差未学習過学習モデルの複雑さ →誤差
モデルを複雑にすると学習データの誤差は下がり続けるが、検証データの誤差はある所から上がる。その谷がちょうど良い複雑さ。
状態症状対策
過学習学習データでは高精度、検証データで低精度(覚えすぎ)データを増やす・データ拡張/正則化(L1・L2)/モデルを単純に/ドロップアウト(NNの一部をランダムに休ませる)/早期終了(検証の成績が悪化し始めたら学習を止める)/特徴量を減らす
未学習学習データでも低精度(表現力不足)モデルを複雑に/特徴量を増やす/正則化を弱める/学習を長く

この2つの綱引きを「バイアスとバリアンスのトレードオフ」と呼びます。

動かしてみる:モデルの複雑さを変える

学習に使う点(12個) 検証用の点  点線=本当の関係 橙の線=モデル(多項式)

次数ごとの誤差。黒=学習データ、橙=検証データ、縦線=今の次数。グラフの上限を超える値は矢印で示す

数式で見る:バイアスとバリアンス
二乗誤差の期待値 = バイアス2 + バリアンス + ノイズ

バイアスはモデルが単純すぎることによる系統的なずれ(未学習)、バリアンスは学習データが少し変わるだけで予測が大きく変わる度合い(過学習)、ノイズはデータ自体のばらつきで、どんなモデルでも減らせません。モデルを複雑にするとバイアスは減り、バリアンスは増えます。

学習の中身:損失関数と最適化

モデルは「予測がどれだけ外れたか」を表す損失関数を小さくするように学びます。回帰では二乗誤差(外れた量の2乗)、分類では交差エントロピー(正解のクラスにどれだけ高い確率を出せたか)が標準です。パラメータを少し動かしたときに損失がどちらへどれだけ変わるか(坂の傾き)を勾配と呼び、勾配を使って損失が下がる方向へ少しずつパラメータを動かすのが勾配降下法です。1歩ごとに使うデータの量によって、全データを使う(バッチ)、1件ずつ使う(確率的勾配降下法 SGD)、少量ずつ使う(ミニバッチ)の3種類があります。深層学習ではミニバッチに Adam などの改良版を組み合わせるのが一般的です。1歩の大きさを決めるのが学習率で、大きすぎると最小の所を飛び越えて発散し、小さすぎると学習が進みません。

損失が最小パラメータ損失
勾配降下法:坂の傾きと逆向きに少しずつ進み、損失が最小の所を探す。傾きが緩むと1歩も小さくなる。

動かしてみる:学習率を変える

損失=w² を、w=−2.6(大きい黒点)から勾配降下法で15歩進めた様子

数式で見る:損失関数と勾配降下法

回帰の損失:平均二乗誤差

MSE = (1/n) Σi (yi − ŷi)2

分類の損失:交差エントロピー(二値。評価指標の対数損失と同じ)

−(1/n) Σi [ yi log pi + (1 − yi) log(1 − pi) ]

正解が1なのに予測確率 p が0に近いと、非常に大きな値になります。

勾配降下法の更新(η=学習率)

w ← w − η · ∂L/∂w

上のデモは L = w2 なので ∂L/∂w = 2w、更新は w ← (1 − 2η)w です。|1 − 2η| < 1、つまり 0 < η < 1 のとき収束します。η = 0.5 なら1歩で0、0.5 < η < 1 なら符号が毎回入れ替わる(振動)、η = 1 なら往復、η > 1 なら発散。デモの動きはこの式どおりです。

ハイパーパラメータの探し方 Hyperparameter tuning

方法特徴
グリッドサーチ候補の全組み合わせを試す。確実だが組み合わせが増えると重い
ランダムサーチランダムに試す。同じ回数ならグリッドより効率的なことが多い
ベイズ最適化過去の結果から有望な値を推測して試す(Optuna など)

理解度チェック

Spark