機械学習の全体地図(3)作って確かめる手順
前処理、データ分割と交差検証、過学習と未学習、損失関数と最適化、ハイパーパラメータの探し方まで、どの手法にも共通する作り方と確かめ方をまとめます。過学習や学習率をスライダーで試せるデモ付き。
連載 機械学習の全体地図 第3回/全8回
④ 手順:どう作り、どう確かめるか
どの手法でも流れは共通です。評価で満足できなければ前の段階に戻ります。Pythonでの書き方は「Pythonで書く」の基本の型を参照してください。
- 課題を定義する業務の目的を、①学び方と②タスクの言葉に置き換え、評価指標と「超えるべき基準(単純な方法の成績)」を決める
- データを集める予測に使う時点で本当に手に入るデータかを確認する
- データを分割する最初にテスト用を取り分け、残りを学習用と検証用に分ける。以降の観察・前処理は学習用データで行う
- データを観察する(EDA)分布、欠損、外れ値、クラスの偏り、変数同士の関係を見る
- 前処理する下の表を参照。平均値など前処理に使う値は学習用データだけで計算し、検証・テストにはその値を当てはめる
- 特徴量を作る業務知識から予測に効く変数を作る(比率、日付の曜日化、集計値など)。効かない変数を減らす特徴量選択もここで行う
- 学習する損失関数(予測の外れ具合を表す数値)が小さくなるようにパラメータを調整する
- 評価する検証用データで指標を計算し、誤りの傾向を分析する。特徴量重要度やSHAPで予測の根拠も確認する
- チューニングするハイパーパラメータ(木の深さなど、人が決める設定)や特徴量を改善し、最後にテスト用データで1回だけ確認
- 本番に載せる他のシステムから呼び出せる形(API)にする、毎晩まとめて予測する処理に組み込む、など
- 監視・再学習する本番データの分布の変化(ドリフト)で精度は落ちるため、定期的に確認し作り直す
前処理の全パターン 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回だけ分ける | データが多いとき |
| k分割交差検証 | k個に分け、1つずつ検証用にしてk回評価し平均。kをデータ件数にしたものを1個抜き交差検証(LOO)と呼ぶ | データが少なめのとき |
| 層化k分割 | 各分割でクラスの比率を揃える | 分類、特に偏りがあるとき |
| 時系列分割 | 必ず過去で学び、未来で検証する | 時系列データ(シャッフル禁止) |
| グループk分割 | 同じ人・同じ店のデータを学習と検証にまたがらせない | 1つの対象から複数行あるとき |
過学習と未学習 Overfitting / Underfitting
| 状態 | 症状 | 対策 |
|---|---|---|
| 過学習 | 学習データでは高精度、検証データで低精度(覚えすぎ) | データを増やす・データ拡張/正則化(L1・L2)/モデルを単純に/ドロップアウト(NNの一部をランダムに休ませる)/早期終了(検証の成績が悪化し始めたら学習を止める)/特徴量を減らす |
| 未学習 | 学習データでも低精度(表現力不足) | モデルを複雑に/特徴量を増やす/正則化を弱める/学習を長く |
この2つの綱引きを「バイアスとバリアンスのトレードオフ」と呼びます。
動かしてみる:モデルの複雑さを変える
学習に使う点(12個) 検証用の点 点線=本当の関係 橙の線=モデル(多項式)
次数ごとの誤差。黒=学習データ、橙=検証データ、縦線=今の次数。グラフの上限を超える値は矢印で示す
数式で見る:バイアスとバリアンス
バイアスはモデルが単純すぎることによる系統的なずれ(未学習)、バリアンスは学習データが少し変わるだけで予測が大きく変わる度合い(過学習)、ノイズはデータ自体のばらつきで、どんなモデルでも減らせません。モデルを複雑にするとバイアスは減り、バリアンスは増えます。
学習の中身:損失関数と最適化
モデルは「予測がどれだけ外れたか」を表す損失関数を小さくするように学びます。回帰では二乗誤差(外れた量の2乗)、分類では交差エントロピー(正解のクラスにどれだけ高い確率を出せたか)が標準です。パラメータを少し動かしたときに損失がどちらへどれだけ変わるか(坂の傾き)を勾配と呼び、勾配を使って損失が下がる方向へ少しずつパラメータを動かすのが勾配降下法です。1歩ごとに使うデータの量によって、全データを使う(バッチ)、1件ずつ使う(確率的勾配降下法 SGD)、少量ずつ使う(ミニバッチ)の3種類があります。深層学習ではミニバッチに Adam などの改良版を組み合わせるのが一般的です。1歩の大きさを決めるのが学習率で、大きすぎると最小の所を飛び越えて発散し、小さすぎると学習が進みません。
動かしてみる:学習率を変える
損失=w² を、w=−2.6(大きい黒点)から勾配降下法で15歩進めた様子
数式で見る:損失関数と勾配降下法
回帰の損失:平均二乗誤差
分類の損失:交差エントロピー(二値。評価指標の対数損失と同じ)
正解が1なのに予測確率 p が0に近いと、非常に大きな値になります。
勾配降下法の更新(η=学習率)
上のデモは 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