# 機能設計書 53-決定木回帰

## 概要

本ドキュメントは、Apache Spark MLlibが提供する決定木回帰（DecisionTreeRegressor）機能の設計を記述する。本機能は、決定木アルゴリズムに基づく回帰モデルの訓練と予測を提供する。

### 本機能の処理概要

決定木回帰は、特徴量空間を再帰的に分割し、各リーフノードで予測値を出力する非パラメトリックな回帰手法である。連続特徴量とカテゴリカル特徴量の両方をサポートする。

**業務上の目的・背景**：決定木は解釈性が非常に高く、人間がモデルの判断根拠を容易に理解できる。非線形関係を自然にモデル化でき、特徴量のスケーリングが不要で、外れ値にも比較的頑健である。

**機能の利用シーン**：解釈性を重視した回帰タスク、特徴量の重要度分析、ランダムフォレストやGBTの基盤アルゴリズムとして利用される。

**主要な処理内容**：
1. カテゴリカル特徴量のメタデータ抽出
2. RandomForest.run()を利用した単一木の訓練（numTrees=1）
3. 不純度（variance）に基づく分割基準の適用
4. 特徴量重要度の算出

**関連システム・外部連携**：RandomForest実装を内部的に利用。MLWritable/MLReadableによるモデル永続化対応。

**権限による制御**：特になし。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 本機能に直接関連する画面はなし |

## 機能種別

計算処理（機械学習 - 決定木回帰）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| maxDepth | Int | No | 木の最大深度（デフォルト: 5） | >= 0 |
| maxBins | Int | No | 連続特徴量の分割ビン数（デフォルト: 32） | >= 2 |
| minInstancesPerNode | Int | No | ノードに必要な最小インスタンス数（デフォルト: 1） | >= 1 |
| minWeightFractionPerNode | Double | No | ノードに必要な最小重み比率（デフォルト: 0.0） | [0, 0.5] |
| minInfoGain | Double | No | 分割に必要な最小情報利得（デフォルト: 0.0） | >= 0 |
| impurity | String | No | 不純度指標（デフォルト: "variance"） | "variance" |
| seed | Long | No | ランダムシード | - |
| weightCol | String | No | 重み列名 | - |
| varianceCol | String | No | 分散予測出力列名 | - |

### 入力データソース

DataFrame形式。ラベル列はDouble型、特徴量列はVector型。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| prediction | Double | 予測値（リーフノードの予測値） |
| variance | Double | 予測分散（varianceCol設定時） |
| leaf | Vector | リーフノードインデックス（leafCol設定時） |

### 出力先

入力DataFrameに予測列を追加。モデルはJSON+ノードデータ形式で永続化。

## 処理フロー

### 処理シーケンス

```
1. カテゴリカル特徴量のメタデータ抽出
   └─ featuresCol のスキーマからカテゴリ情報を取得
2. 訓練インスタンスの構築
   └─ (label, weight, features) のRDDを生成
3. 訓練戦略の構築
   └─ OldStrategy（Algo=Regression, Impurity=Variance）を生成
4. RandomForest.runで単一木訓練
   └─ numTrees=1, featureSubsetStrategy="all"
5. DecisionTreeRegressionModelとして返却
```

### フローチャート

```mermaid
flowchart TD
    A[開始: train] --> B[カテゴリカル特徴量抽出]
    B --> C[訓練インスタンス構築]
    C --> D[訓練戦略生成]
    D --> E[RandomForest.run numTrees=1]
    E --> F[DecisionTreeRegressionModel]
    F --> G[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-53-01 | ブートストラップ不使用 | DecisionTreeRegressorはブートストラップサンプリングを使用しない | 常時 |
| BR-53-02 | 不純度指標 | 回帰では"variance"のみサポート | 常時 |
| BR-53-03 | 全特徴量使用 | featureSubsetStrategy="all"で全特徴量を使用 | 常時 |
| BR-53-04 | 特徴量重要度 | ノードの分割利得とインスタンス数に基づいて正規化された重要度を算出 | featureImportances呼出時 |

### 計算ロジック

- 予測: `rootNode.predictImpl(features).prediction`（リーフノードへの分岐結果）
- 分散予測: `rootNode.predictImpl(features).impurityStats.calculate()`
- 特徴量重要度: 各分割ノードの利得をインスタンス数で重み付けし、合計を1に正規化

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

本機能はデータベース操作を行わない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | RequireError | rootNodeがnullの場合 | 正常な訓練データを使用 |
| - | RequireError | bootstrapがtrueの場合 | 決定木はブートストラップ不要 |

### リトライ仕様

特になし。

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

Sparkの遅延評価に基づく。

## パフォーマンス要件

- cacheNodeIdsパラメータでノードIDキャッシュを制御
- maxMemoryInMBで学習時のメモリ使用量を制御
- checkpointIntervalでチェックポイント間隔を設定

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

Sparkの標準セキュリティ機構に従う。

## 備考

- Spark 1.4.0で導入
- 内部的にRandomForest.runを使用（numTrees=1の特殊ケース）
- 単一決定木の特徴量重要度は分散が大きいため、RandomForestRegressorの使用を推奨

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | DecisionTreeRegressor.scala | `mllib/src/main/scala/org/apache/spark/ml/regression/DecisionTreeRegressor.scala` | DecisionTreeRegressorParams（ツリー関連トレイト）の継承構造を確認 |
| 1-2 | Node.scala | `mllib/src/main/scala/org/apache/spark/ml/tree/Node.scala` | Node, InternalNode, LeafNodeのデータ構造を確認 |

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | DecisionTreeRegressor.scala | 同上 | train()（116-140行目）が訓練のエントリーポイント |

**主要処理フロー**:
1. **118-119行目**: カテゴリカル特徴量情報の抽出
2. **121-126行目**: 訓練インスタンスRDDの構築
3. **128行目**: OldStrategy生成
4. **136-137行目**: RandomForest.run()で単一木の訓練
5. **139行目**: 結果をDecisionTreeRegressionModelにキャスト

#### Step 3: モデルの予測処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | DecisionTreeRegressor.scala | 同上 | transform()（217-251行目）で予測・分散・リーフのUDF適用 |
| 3-2 | DecisionTreeRegressor.scala | 同上 | predict()（195-197行目）でルートノードから予測値を取得 |

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

```
DecisionTreeRegressor.train(dataset)
    |
    +-- MetadataUtils.getCategoricalFeatures()
    +-- getOldStrategy(categoricalFeatures)
    +-- RandomForest.run(instances, strategy, numTrees=1, "all")
            |
            +-- [内部的な木構築アルゴリズム]
            +-- DecisionTreeRegressionModel(rootNode, numFeatures)

DecisionTreeRegressionModel.transform(dataset)
    |
    +-- predict(features)
    |       +-- rootNode.predictImpl(features).prediction
    +-- predictVariance(features) [optional]
    +-- predictLeaf(features) [optional]
```

### データフロー図

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

DataFrame          train()
  (label,          +-- カテゴリ情報抽出          DecisionTreeRegressionModel
   features,       +-- Strategy構築                (rootNode,
   weight)         +-- RandomForest.run()            numFeatures)

DataFrame          transform()
  (features)       +-- rootNode.predictImpl()    DataFrame
                                                   (prediction,
                                                    variance,
                                                    leaf)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| DecisionTreeRegressor.scala | `mllib/src/main/scala/org/apache/spark/ml/regression/DecisionTreeRegressor.scala` | ソース | Estimator/Model の実装 |
| RandomForest.scala | `mllib/src/main/scala/org/apache/spark/ml/tree/impl/RandomForest.scala` | ソース | 実際のツリー構築アルゴリズム |
| Node.scala | `mllib/src/main/scala/org/apache/spark/ml/tree/Node.scala` | ソース | ツリーノードのデータ構造 |
| treeParams.scala | `mllib/src/main/scala/org/apache/spark/ml/tree/treeParams.scala` | ソース | ツリー関連パラメータ定義 |
| DecisionTreeModelReadWrite.scala | `mllib/src/main/scala/org/apache/spark/ml/tree/DecisionTreeModelReadWrite.scala` | ソース | モデルの永続化 |
