# 機能設計書 70-統計検定

## 概要

本ドキュメントは、Apache Spark MLlibにおける統計検定機能の設計を記述する。ml.statパッケージに含まれるカイ二乗検定、ANOVA検定、F値検定、相関分析、コルモゴロフ・スミルノフ検定、およびSummarizer（統計量集約）機能を対象とする。

### 本機能の処理概要

**業務上の目的・背景**：機械学習における特徴量選択や、データの統計的性質の検証は、モデル構築の前段階で不可欠な工程である。統計検定機能は、特徴量とラベルの独立性検定、分布の適合度検定、特徴量間の相関分析、基本統計量の集約などを提供し、データ理解とモデル構築を支援する。

**機能の利用シーン**：特徴量選択（カイ二乗検定でカテゴリ特徴量の有用性を評価）、データ探索（相関分析で特徴量間の関連性を把握）、分布検証（KS検定でデータが理論分布に従うか検定）、ANOVA分析（カテゴリラベルに対する連続特徴量の有意性検定）、基本統計量の算出（平均、分散、最小値、最大値等）。

**主要な処理内容**：
1. **ChiSquareTest**: カテゴリ特徴量とカテゴリラベルの独立性検定（ピアソンのカイ二乗検定）
2. **ANOVATest**: カテゴリラベルに対する連続特徴量の分散分析
3. **FValueTest**: 連続ラベルに対する連続特徴量のF値検定
4. **Correlation**: ピアソンまたはスピアマン相関行列の算出
5. **KolmogorovSmirnovTest**: データが指定の理論分布に従うかの適合度検定
6. **Summarizer**: Vector型カラムの基本統計量（平均、分散、カウント、最小、最大等）の集約

**関連システム・外部連携**：Spark DataFrame APIと統合。mllib.stat.Statisticsおよびmllib.stat.testに計算を委譲。Summarizerはカスタム集約式としてDataFrame APIのselect()内で使用可能。

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

## 関連画面

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

## 機能種別

計算処理（統計分析 - 仮説検定・相関分析）

## 入力仕様

### 入力パラメータ

#### ChiSquareTest
| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| dataset | DataFrame | Yes | 入力データ | - |
| featuresCol | String | Yes | 特徴量カラム名 | Vector型（VectorUDT） |
| labelCol | String | Yes | ラベルカラム名 | 数値型 |
| flatten | Boolean | No | 結果を1行/特徴量にするか（デフォルト: false） | - |

#### Correlation
| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| dataset | Dataset | Yes | 入力データ | - |
| column | String | Yes | Vector型カラム名 | Vector型 |
| method | String | No | 相関手法（"pearson"/"spearman"、デフォルト: "pearson"） | - |

#### KolmogorovSmirnovTest
| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| dataset | Dataset | Yes | 入力データ | - |
| sampleCol | String | Yes | サンプルカラム名 | 数値型 |
| cdf | Double => Double | Yes* | 理論CDF関数 | - |
| distName | String | Yes* | 分布名（"norm"） | - |
| params | Double* | No | 分布パラメータ（平均、分散） | - |

#### Summarizer
| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| featuresCol | Column | Yes | 特徴量カラム | Vector型 |
| weightCol | Column | No | 重みカラム（デフォルト: 1.0） | - |
| metrics | String* | Yes | 要求する統計量（"mean", "sum", "variance", "std", "count", "numNonZeros", "max", "min", "normL1", "normL2", "normInf"） | - |

### 入力データソース

Spark DataFrame。各検定が要求するカラム型に従った入力データ。

## 出力仕様

### 出力データ

#### ChiSquareTest
| 項目名 | 型 | 説明 |
|--------|-----|------|
| pValues | Vector | 各特徴量のp値 |
| degreesOfFreedom | Array[Int] | 各特徴量の自由度 |
| statistics | Vector | 各特徴量のカイ二乗統計量 |

#### Correlation
| 項目名 | 型 | 説明 |
|--------|-----|------|
| method(column) | Matrix | 相関行列 |

#### KolmogorovSmirnovTest
| 項目名 | 型 | 説明 |
|--------|-----|------|
| pValue | Double | p値 |
| statistic | Double | KS統計量 |

#### Summarizer
| 項目名 | 型 | 説明 |
|--------|-----|------|
| mean | Vector | 平均ベクトル |
| variance | Vector | 分散ベクトル |
| count | Long | サンプル数 |
| min / max | Vector | 最小/最大ベクトル |
| その他 | 各種 | 指定したメトリクスに応じた統計量 |

### 出力先

各test()メソッドがDataFrameを返す。Summarizerはselect()内のColumn式として使用。

## 処理フロー

### 処理シーケンス

```
1. スキーマバリデーション
   └─ 入力カラムの型チェック
2. データの抽出とRDD変換
   └─ DataFrame → RDD[(label, features)]またはRDD[Vector]変換
3. mllib統計計算への委譲
   └─ OldChiSqTest / OldStatistics.corr / OldStatistics.kolmogorovSmirnovTest
4. 結果のDataFrame変換
   └─ テスト結果をDataFrameとして構成
```

### フローチャート

```mermaid
flowchart TD
    A[開始: test/corr呼び出し] --> B[スキーマ検証]
    B --> C[DataFrame → RDD変換]
    C --> D{検定種別}
    D -->|ChiSquare| E[OldChiSqTest.computeChiSquared]
    D -->|Correlation| F[OldStatistics.corr]
    D -->|KS| G[OldStatistics.kolmogorovSmirnovTest]
    D -->|ANOVA| H[ANOVA計算]
    D -->|FValue| I[F値計算]
    E --> J[結果DataFrame生成]
    F --> J
    G --> J
    H --> J
    I --> J
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-70-01 | ChiSquare前提 | 特徴量・ラベルともにカテゴリ（離散）データであること | ChiSquareTest |
| BR-70-02 | ANOVA前提 | ラベルがカテゴリ、特徴量が連続データであること | ANOVATest |
| BR-70-03 | FValue前提 | ラベル・特徴量ともに連続データであること | FValueTest |
| BR-70-04 | KS検定 | 両側検定を実施 | KolmogorovSmirnovTest |
| BR-70-05 | Spearman相関 | ランク相関のためRDDソートが必要で計算コストが高い | Correlation(method="spearman") |
| BR-70-06 | flatten | flatten=trueで特徴量ごとに1行の結果、falseで全特徴量を1行に集約 | ChiSquare/ANOVA/FValue |

### 計算ロジック

- カイ二乗統計量: chi2 = sum((O_ij - E_ij)^2 / E_ij)
- ピアソン相関: r = cov(X,Y) / (std(X) * std(Y))
- KS統計量: D = max|F_n(x) - F(x)|（経験分布と理論分布の最大差）
- F値: F = (間グループ分散) / (内グループ分散)

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

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| IllegalArgumentException | スキーマエラー | featuresColがVector型でない | Vector型カラムを指定 |
| IllegalArgumentException | スキーマエラー | labelCol/sampleColが数値型でない | 数値型カラムを指定 |
| IllegalArgumentException | パラメータエラー | methodが"pearson"/"spearman"以外 | 有効な手法名を指定 |

### リトライ仕様

リトライ機構は組み込まれていない。

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

トランザクション管理なし。

## パフォーマンス要件

Spearman相関はランクソートが必要なため、Pearson相関より計算コストが高い。入力DatasetをキャッシュしてからSpearman相関を実行することを推奨。Summarizerは2-3倍のオーバーヘッドがあるがDataFrame APIで直接使用可能。

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

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

## 備考

- ChiSquareTest/Correlation: Spark 2.2.0で導入
- KolmogorovSmirnovTest: Spark 2.4.0で導入
- ANOVATest/FValueTest: Spark 3.1.0で導入（private[ml]）
- Summarizer: Spark 2.3.0で導入
- ANOVATest/FValueTestはprivate[ml]スコープのため、ChiSqSelectorやUnivariateFeatureSelector経由で使用

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ChiSquareTest.scala | `mllib/src/main/scala/org/apache/spark/ml/stat/ChiSquareTest.scala` | **35行目**: objectとして定義。test()メソッドのシグネチャ確認 |
| 1-2 | Correlation.scala | `mllib/src/main/scala/org/apache/spark/ml/stat/Correlation.scala` | **36行目**: objectとして定義。corr()メソッドのシグネチャ確認 |

**読解のコツ**: 統計検定機能はすべてobjectのメソッドとして提供され、Estimator/Transformerパターンではない。DataFrame入力→DataFrame出力の関数的スタイル。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | ChiSquareTest.scala | `mllib/src/main/scala/org/apache/spark/ml/stat/ChiSquareTest.scala` | **69-100行目**: test()メソッド |

**主要処理フロー**:
1. **74行目**: SchemaUtils.checkColumnTypeでVector型チェック
2. **75行目**: SchemaUtils.checkNumericTypeでラベル型チェック
3. **80-81行目**: DataFrame → RDD[(label, OldVector)]変換
4. **83-86行目**: OldChiSqTest.computeChiSquaredで計算
5. **88-99行目**: flatten有無で結果DataFrame形式を分岐

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Correlation.scala | `mllib/src/main/scala/org/apache/spark/ml/stat/Correlation.scala` | **67-75行目**: corr()メソッド |

**主要処理フロー**:
1. **68-69行目**: DataFrame → RDD[OldVector]変換
2. **71行目**: OldStatistics.corr()で相関行列計算
3. **72-74行目**: 結果をMatrix型のDataFrameに変換

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | KolmogorovSmirnovTest.scala | `mllib/src/main/scala/org/apache/spark/ml/stat/KolmogorovSmirnovTest.scala` | **40-116行目**: KolmogorovSmirnovTestオブジェクト |

**主要処理フロー**:
- **47-51行目**: getSampleRDD()でDouble RDD生成
- **68-75行目**: カスタムCDF版test()
- **105-115行目**: 分布名指定版test()

#### Step 5: Summarizerを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | Summarizer.scala | `mllib/src/main/scala/org/apache/spark/ml/stat/Summarizer.scala` | **47-61行目**: SummaryBuilder抽象クラス、**89行目以降**: Summarizerオブジェクト |

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

```
ChiSquareTest.test(dataset, featuresCol, labelCol)
    |
    +-- SchemaUtils検証
    +-- dataset → RDD[(Double, OldVector)]
    +-- OldChiSqTest.computeChiSquared(data)
    +-- 結果DataFrame生成

Correlation.corr(dataset, column, method)
    |
    +-- dataset → RDD[OldVector]
    +-- OldStatistics.corr(rdd, method)
    +-- Matrix → DataFrame変換

KolmogorovSmirnovTest.test(dataset, sampleCol, cdf/distName)
    |
    +-- getSampleRDD(dataset, sampleCol)
    +-- OldStatistics.kolmogorovSmirnovTest(rdd, cdf)
    +-- KolmogorovSmirnovTestResult → DataFrame

Summarizer.metrics("mean", "std", ...)
    |
    +-- SummaryBuilder生成
    +-- .summary(featuresCol, weightCol) → Column
    +-- DataFrame.select()内で使用
```

### データフロー図

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

DataFrame              ChiSquareTest.test()           DataFrame
(features,         --> OldChiSqTest計算            --> (pValues, dof,
 label)                                                 statistics)

DataFrame              Correlation.corr()             DataFrame
(features:         --> OldStatistics.corr()        --> (correlation: Matrix)
 Vector)

DataFrame              KSTest.test()                  DataFrame
(sample:           --> OldStatistics.ksTest()       --> (pValue, statistic)
 Double)

DataFrame              Summarizer.metrics()           Column
(features:         --> SummaryBuilder               --> (mean, std, count,
 Vector)               .summary(col)                    min, max, ...)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| ChiSquareTest.scala | `mllib/src/main/scala/org/apache/spark/ml/stat/ChiSquareTest.scala` | ソース | カイ二乗検定 |
| Correlation.scala | `mllib/src/main/scala/org/apache/spark/ml/stat/Correlation.scala` | ソース | 相関分析 |
| KolmogorovSmirnovTest.scala | `mllib/src/main/scala/org/apache/spark/ml/stat/KolmogorovSmirnovTest.scala` | ソース | KS検定 |
| Summarizer.scala | `mllib/src/main/scala/org/apache/spark/ml/stat/Summarizer.scala` | ソース | 統計量集約 |
| ANOVATest.scala | `mllib/src/main/scala/org/apache/spark/ml/stat/ANOVATest.scala` | ソース | ANOVA検定 |
| FValueTest.scala | `mllib/src/main/scala/org/apache/spark/ml/stat/FValueTest.scala` | ソース | F値検定 |
| Statistics.scala | `mllib/src/main/scala/org/apache/spark/mllib/stat/Statistics.scala` | ソース | MLlib層の統計計算 |
| ChiSqTest.scala | `mllib/src/main/scala/org/apache/spark/mllib/stat/test/ChiSqTest.scala` | ソース | MLlib層のカイ二乗検定 |
