# 機能設計書 68-ハイパーパラメータチューニング

## 概要

本ドキュメントは、Apache Spark MLlibにおけるハイパーパラメータチューニング機能の設計を記述する。CrossValidatorおよびTrainValidationSplitによるモデル選択と、ParamGridBuilderによるパラメータグリッド構築機能を対象とする。

### 本機能の処理概要

**業務上の目的・背景**：機械学習モデルのハイパーパラメータは手動での最適化が困難であり、体系的な探索が必要である。CrossValidator（K分割交差検証）とTrainValidationSplit（訓練/検証分割）の2つの手法を提供し、ParamGridBuilderで定義されたパラメータグリッドを網羅的に評価して最適なパラメータ組み合わせを自動選択する。

**機能の利用シーン**：機械学習パイプラインの最終段階において、最適なハイパーパラメータを自動探索する場面で利用される。モデルの汎化性能を評価しながらパラメータを選択するため、過学習の防止にも寄与する。

**主要な処理内容**：
1. ParamGridBuilderでパラメータ候補の直積グリッドを構築
2. CrossValidator: データをK分割し、各フォールドで訓練/検証を繰り返す
3. TrainValidationSplit: データを1回のランダム分割で訓練/検証を行う
4. 各パラメータ組み合わせでEvaluatorによるメトリクスを算出
5. 最良メトリクスのパラメータ組み合わせでモデルを再訓練

**関連システム・外部連携**：Estimator、Evaluator、ParamMapと密接に連携。Pipeline APIと組み合わせてパイプライン全体のチューニングが可能。並列実行（parallelism）サポートによる高速化。

**権限による制御**：特になし。Sparkアプリケーション実行権限に依存する。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | 該当なし | - | MLlib機能はWeb UIに専用画面を持たない |

## 機能種別

計算処理（機械学習 - モデル選択・チューニング）

## 入力仕様

### 入力パラメータ

#### CrossValidator
| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| estimator | Estimator | Yes | チューニング対象のEstimator | - |
| estimatorParamMaps | Array[ParamMap] | Yes | パラメータグリッド | - |
| evaluator | Evaluator | Yes | 評価器 | - |
| numFolds | Int | No | 分割数（デフォルト: 3） | >= 2 |
| seed | Long | No | 乱数シード | - |
| parallelism | Int | No | 並列評価数（デフォルト: 1） | >= 1 |
| collectSubModels | Boolean | No | サブモデル保存（デフォルト: false） | - |
| foldCol | String | No | ユーザー指定フォールドカラム名（デフォルト: ""） | 整数型、[0, numFolds) |

#### TrainValidationSplit
| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| estimator | Estimator | Yes | チューニング対象のEstimator | - |
| estimatorParamMaps | Array[ParamMap] | Yes | パラメータグリッド | - |
| evaluator | Evaluator | Yes | 評価器 | - |
| trainRatio | Double | No | 訓練データ比率（デフォルト: 0.75） | [0, 1] |
| seed | Long | No | 乱数シード | - |
| parallelism | Int | No | 並列評価数（デフォルト: 1） | >= 1 |
| collectSubModels | Boolean | No | サブモデル保存（デフォルト: false） | - |

#### ParamGridBuilder
| メソッド | 説明 |
|---------|------|
| addGrid(param, values) | パラメータに複数の候補値を追加 |
| baseOn(paramMap) | 固定パラメータを設定 |
| build() | 全組み合わせのParamMap配列を生成 |

### 入力データソース

Spark DataFrame。Estimatorのfit()が受け入れる形式のデータ。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| bestModel | Model | 最良パラメータで訓練されたモデル |
| avgMetrics | Array[Double] | 各パラメータ組み合わせの平均メトリクス（CrossValidator） |
| validationMetrics | Array[Double] | 各パラメータ組み合わせの検証メトリクス（TrainValidationSplit） |
| subModels | Array[Array[Model]] | サブモデル（collectSubModels=true時） |

### 出力先

CrossValidatorModel / TrainValidationSplitModel。bestModelを内包し、transform()でbestModelを使用する。

## 処理フロー

### 処理シーケンス

```
1. パラメータグリッドの取得
   └─ estimatorParamMapsから全パラメータ組み合わせを取得
2. データ分割
   └─ CrossValidator: K分割 / TrainValidationSplit: trainRatio分割
3. 各フォールド/分割での評価
   └─ 各パラメータ組み合わせでEstimator.fit() → Evaluator.evaluate()
4. メトリクスの集約
   └─ CrossValidator: フォールド平均 / TrainValidationSplit: 単一値
5. 最良パラメータの選択
   └─ isLargerBetter=trueなら最大、falseなら最小を選択
6. 全データで再訓練
   └─ 最良パラメータで全データに対してfit()を実行
7. モデルの返却
   └─ CrossValidatorModel / TrainValidationSplitModelを返却
```

### フローチャート

```mermaid
flowchart TD
    A[開始: fit呼び出し] --> B[パラメータグリッド取得]
    B --> C{CrossValidator or TVS?}
    C -->|CrossValidator| D[K分割]
    C -->|TVS| E[trainRatio分割]
    D --> F[各フォールドで訓練/検証]
    E --> G[訓練/検証]
    F --> H[フォールド平均メトリクス計算]
    G --> I[検証メトリクス計算]
    H --> J[最良パラメータ選択]
    I --> J
    J --> K[全データで再訓練]
    K --> L[モデル返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-68-01 | 最良モデル選択 | evaluator.isLargerBetter=trueなら最大メトリクス、falseなら最小メトリクスのパラメータを選択 | 常時 |
| BR-68-02 | K分割交差検証 | 各フォールドが検証データとして1回ずつ使用される | CrossValidator |
| BR-68-03 | 並列実行 | parallelismで指定した数のモデルを並列に訓練・評価 | parallelism > 1 |
| BR-68-04 | foldCol指定 | foldColが指定された場合、ランダムK分割ではなくユーザー指定分割を使用 | CrossValidator |
| BR-68-05 | サブモデル保存 | collectSubModels=trueの場合、各パラメータ/フォールドのサブモデルを保持 | collectSubModels=true |

### 計算ロジック

CrossValidator平均メトリクス: avg_metric(p) = sum(metric(p, fold_i)) / numFolds

## データベース操作仕様

### 操作別データベース影響一覧

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| - | - | - | データベース操作なし（インメモリ処理） |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| IllegalArgumentException | パラメータ検証エラー | numFolds < 2 | numFoldsを2以上に設定 |
| IllegalArgumentException | パラメータ検証エラー | trainRatioが[0,1]範囲外 | 有効な比率を指定 |
| IllegalArgumentException | 型エラー | foldColが整数型でない | 整数型カラムを指定 |

### リトライ仕様

リトライ機構は組み込まれていない。各フォールドの訓練は独立して実行される。

## トランザクション仕様

トランザクション管理なし。各フォールドのデータセットはキャッシュされ、全メトリクス算出後にアンパーシストされる。

## パフォーマンス要件

parallelismパラメータにより並列実行を制御。K分割 x パラメータ組み合わせ数のモデル訓練が必要なため、計算コストが高い。TrainValidationSplitはCrossValidatorより計算コストが低い。

## セキュリティ考慮事項

特段のセキュリティ制御なし。

## 備考

- CrossValidatorModel/TrainValidationSplitModelはMLWritableで永続化可能
- persistSubModelsオプションでサブモデルも永続化可能
- CrossValidatorModelはローカルファイルシステムへの保存は未サポート
- foldColにより再現可能なフォールド分割が可能

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ParamGridBuilder.scala | `mllib/src/main/scala/org/apache/spark/ml/tuning/ParamGridBuilder.scala` | **30-120行目**: パラメータグリッド構築。addGrid()で候補値追加、build()で直積生成 |

**読解のコツ**: build()メソッド（110-119行目）で、各パラメータの候補値の直積（全組み合わせ）を生成する。paramGridマップを順次展開し、flatMapで全組み合わせを作成する。

#### Step 2: CrossValidatorを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | CrossValidator.scala | `mllib/src/main/scala/org/apache/spark/ml/tuning/CrossValidator.scala` | **47-72行目**: CrossValidatorParamsでnumFolds/foldCol定義 |
| 2-2 | CrossValidator.scala | `mllib/src/main/scala/org/apache/spark/ml/tuning/CrossValidator.scala` | **82-235行目**: CrossValidatorクラス |

**主要処理フロー**:
1. **139行目**: fit()のエントリーポイント
2. **148行目**: parallelismに基づくExecutionContext生成
3. **162-167行目**: K分割データ生成（foldCol有無で分岐）
4. **168-194行目**: 各フォールドで各パラメータ組み合わせの訓練・評価をFutureで並列実行
5. **194行目**: transpose + 平均メトリクス計算
6. **198-200行目**: 最良パラメータ選択（isLargerBetterに基づく）
7. **203行目**: 全データで再訓練
8. **204-205行目**: CrossValidatorModelの生成

#### Step 3: CrossValidatorModelを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | CrossValidator.scala | `mllib/src/main/scala/org/apache/spark/ml/tuning/CrossValidator.scala` | **284-361行目**: CrossValidatorModelクラス |

**主要処理フロー**:
- **332-335行目**: transform()はbestModel.transform()に委譲
- **322-326行目**: subModelsアクセス

#### Step 4: TrainValidationSplitを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | TrainValidationSplit.scala | `mllib/src/main/scala/org/apache/spark/ml/tuning/TrainValidationSplit.scala` | **47-61行目**: TrainValidationSplitParamsでtrainRatio定義 |

### プログラム呼び出し階層図

```
CrossValidator.fit(dataset)
    |
    +-- getExecutionContext (parallelism)
    |
    +-- MLUtils.kFold(dataset, numFolds, seed)
    |       └─ K個の(training, validation)ペア生成
    |
    +-- splits.zipWithIndex.map { (training, validation) =>
    |       +-- epm.zipWithIndex.map { paramMap =>
    |       |       +-- Future { est.fit(training, paramMap) }
    |       |       +-- eval.evaluate(model.transform(validation))
    |       |       }
    |       +-- ThreadUtils.awaitResult(foldMetricFutures)
    |       }
    |
    +-- metrics.transpose.map(_.sum / numFolds)  // 平均メトリクス
    |
    +-- (bestMetric, bestIndex) = maxBy/minBy
    |
    +-- est.fit(dataset, epm(bestIndex))  // 全データで再訓練
    |
    +-- CrossValidatorModel(uid, bestModel, avgMetrics)
```

### データフロー図

```
[入力]                        [処理]                              [出力]

ParamGridBuilder         CrossValidator.fit()             CrossValidatorModel
  .build()           --> K分割 x パラメータグリッド      --> (bestModel,
  → ParamMap[]           各組み合わせで訓練/評価              avgMetrics,
                         平均メトリクス算出                    subModels?)
DataFrame                最良パラメータ選択
                         全データで再訓練
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| CrossValidator.scala | `mllib/src/main/scala/org/apache/spark/ml/tuning/CrossValidator.scala` | ソース | K分割交差検証 |
| TrainValidationSplit.scala | `mllib/src/main/scala/org/apache/spark/ml/tuning/TrainValidationSplit.scala` | ソース | 訓練/検証分割 |
| ParamGridBuilder.scala | `mllib/src/main/scala/org/apache/spark/ml/tuning/ParamGridBuilder.scala` | ソース | パラメータグリッド構築 |
| ValidatorParams.scala | `mllib/src/main/scala/org/apache/spark/ml/tuning/ValidatorParams.scala` | ソース | 共通パラメータ定義 |
