# 機能設計書 58-Factorization-Machines回帰

## 概要

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

### 本機能の処理概要

Factorization Machines（FM）は、特徴量間のペアワイズ交互作用を低ランク因子行列でモデル化する手法である。高次元スパースデータにおいて、明示的な交互作用特徴量を定義することなく、特徴量間の相互作用を学習できる。

**業務上の目的・背景**：レコメンデーションシステムや広告クリック予測など、大規模スパースデータの回帰・分類で高い性能を発揮する。従来の線形モデルでは捉えられない特徴量間の交互作用効果を効率的にモデル化する。

**機能の利用シーン**：レコメンデーション（ユーザー-アイテム相互作用）、クリック率予測（広告特徴量間の交互作用）、スパースデータの回帰予測で利用される。

**主要な処理内容**：
1. 因子行列（factorSize x numFeatures）の初期化
2. 勾配降下法（GD）またはAdamWオプティマイザによる最適化
3. MSE損失に基づく係数更新
4. 切片（intercept）、線形項（linear）、因子項（factors）の分離管理

**関連システム・外部連携**：mllib GradientDescentオプティマイザ、AdamWUpdater。

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

## 関連画面

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

## 機能種別

計算処理（機械学習 - Factorization Machines回帰）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| factorSize | Int | No | 因子の次元数（デフォルト: 8） | > 0 |
| fitIntercept | Boolean | No | 切片推定（デフォルト: true） | - |
| fitLinear | Boolean | No | 線形項推定（デフォルト: true） | - |
| regParam | Double | No | L2正則化パラメータ（デフォルト: 0.0） | >= 0 |
| miniBatchFraction | Double | No | ミニバッチ比率（デフォルト: 1.0） | (0, 1] |
| initStd | Double | No | 初期係数の標準偏差（デフォルト: 0.01） | > 0 |
| maxIter | Int | No | 最大反復回数（デフォルト: 100） | >= 0 |
| stepSize | Double | No | 学習率（デフォルト: 1.0） | > 0 |
| tol | Double | No | 収束判定閾値（デフォルト: 1E-6） | >= 0 |
| solver | String | No | オプティマイザ（デフォルト: "adamW"） | "gd", "adamW" |
| seed | Long | No | ランダムシード | - |

### 入力データソース

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

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| prediction | Double | 予測値（intercept + linear + pairwise interactions） |
| intercept | Double | 切片（モデル属性） |
| linear | Vector | 線形項係数（モデル属性） |
| factors | Matrix | 因子行列（numFeatures x factorSize）（モデル属性） |

### 出力先

入力DataFrameに予測列を追加。

## 処理フロー

### 処理シーケンス

```
1. 特徴量数の取得
2. データ準備（OldVectors形式に変換）
3. 係数の初期化（正規乱数 * initStd）
4. 勾配降下法による最適化
   └─ MSEFactorizationMachinesGradient + GD/AdamWUpdater
5. 係数の分離（intercept, linear, factors）
6. FMRegressionModel生成
```

### フローチャート

```mermaid
flowchart TD
    A[開始: train] --> B[特徴量数取得]
    B --> C[データ準備・キャッシュ]
    C --> D[係数初期化: N(0, initStd)]
    D --> E[MSEGradient + Updater構築]
    E --> F{solver選択}
    F -->|gd| G[SquaredL2Updater]
    F -->|adamW| H[AdamWUpdater]
    G --> I[GradientDescent最適化]
    H --> I
    I --> J[係数分離: intercept + linear + factors]
    J --> K[FMRegressionModel生成]
    K --> L[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-58-01 | 損失関数 | 回帰タスクではSquaredError損失を使用 | 常時 |
| BR-58-02 | 係数構造 | 係数ベクトル = [factors(k*n) + linear(n) + intercept(1)] | 訓練時 |
| BR-58-03 | 予測式 | y = w0 + sum(wi*xi) + sum_pairs(<vi,vj>*xi*xj) | 予測時 |

### 計算ロジック

FM予測式:
```
y = w0 + sum_{i=1}^{n} w_i * x_i + sum_{i=1}^{n} sum_{j=i+1}^{n} <v_i, v_j> * x_i * x_j
```

ペアワイズ交互作用項の効率的計算（O(kn)）:
```
sum_pairs = 0.5 * sum_{f=1}^{k} [ (sum_{i=1}^{n} v_{i,f} * x_i)^2 - sum_{i=1}^{n} v_{i,f}^2 * x_i^2 ]
```

AdamWオプティマイザ（Loshchilov & Hutter, 2019）:
- beta1=0.9, beta2=0.999, epsilon=1e-8
- Weight decay正則化をL2正則化から分離

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | IllegalArgumentException | 未サポートの損失関数 | squaredErrorを使用 |
| - | RequireError | 係数サイズ不一致 | 内部エラー（通常発生しない） |

### リトライ仕様

特になし。

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

Sparkの遅延評価に基づく。

## パフォーマンス要件

- スパースベクトルに最適化された勾配計算（SparseVector専用パス）
- miniBatchFractionで各反復のデータ使用量を制御

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

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

## 備考

- Spark 3.0.0で導入
- S. Rendle "Factorization machines" (2010)に基づく実装
- AdamWオプティマイザはLoshchilov & Hutter (2019)に基づく
- スパースデータに特に効果的

---

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | FMRegressor.scala | `mllib/src/main/scala/org/apache/spark/ml/regression/FMRegressor.scala` | FactorizationMachinesParams（51-122行目）でfactorSize, fitLinear等のFM固有パラメータ |
| 1-2 | FMRegressor.scala | 同上 | splitCoefficients()（208-231行目）で係数ベクトルの分離構造を理解 |

**読解のコツ**: FM係数はfactors(k*n) + linear(n) + intercept(1)の1次元ベクトルとして管理され、splitCoefficientsで分離される。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | FMRegressor.scala | 同上 | train()（411-441行目） |

**主要処理フロー**:
1. **420行目**: 特徴量数取得
2. **425-429行目**: データをOldVectors形式に変換
3. **433行目**: trainImpl呼出し（SquaredError損失）
4. **435-436行目**: 係数をintercept, linear, factorsに分離
5. **440行目**: FMRegressionModel生成

#### Step 3: 訓練処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | FMRegressor.scala | 同上 | FactorizationMachines.trainImpl()（136-159行目）で初期化・オプティマイザ構築・最適化 |
| 3-2 | FMRegressor.scala | 同上 | initCoefficients()（126-134行目）で正規乱数による初期化 |

#### Step 4: 勾配計算を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | FMRegressor.scala | 同上 | BaseFactorizationMachinesGradient（612-720行目）で勾配計算の基底クラス |
| 4-2 | FMRegressor.scala | 同上 | MSEFactorizationMachinesGradient（781-803行目）でMSE損失の乗数 |
| 4-3 | FMRegressor.scala | 同上 | getRawPrediction()（637-661行目）で予測値とsumVXの計算 |

**読解のコツ**: getRawGradient()はスパース/密ベクトルで処理パスが異なる。SparseVector用パスでは必要な要素のみ計算する最適化が行われている。

#### Step 5: AdamWオプティマイザを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | FMRegressor.scala | 同上 | AdamWUpdater（818-853行目）でAdamW更新則 |

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

```
FMRegressor.train(dataset)
    |
    +-- getNumFeatures(dataset)
    +-- データをRDD[(Double, OldVector)]に変換
    +-- trainImpl(data, numFeatures, SquaredError)
    |       +-- initCoefficients(numFeatures) [正規乱数初期化]
    |       +-- parseLoss() -> MSEFactorizationMachinesGradient
    |       +-- parseSolver() -> SquaredL2Updater / AdamWUpdater
    |       +-- GradientDescent.optimizeWithLossReturned()
    |
    +-- splitCoefficients(coefficients) -> (intercept, linear, factors)
    +-- new FMRegressionModel(uid, intercept, linear, factors)

FMRegressionModel.predict(features)
    |
    +-- getRawPrediction(features, intercept, linear, factors)
            +-- intercept + features.dot(linear)
            +-- 0.5 * sum_f[(sum_i v_if*xi)^2 - sum_i v_if^2*xi^2]
```

### データフロー図

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

DataFrame          train()
  (label,          +-- OldVectors変換                FMRegressionModel
   features)       +-- 正規乱数で初期化                 (intercept,
                   +-- GD/AdamW最適化                    linear,
                   +-- 係数分離                           factors)

DataFrame          predict()
  (features)       +-- w0 + Xw + pairs              DataFrame
                                                       (prediction)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| FMRegressor.scala | `mllib/src/main/scala/org/apache/spark/ml/regression/FMRegressor.scala` | ソース | Estimator/Model/Gradient/Updater全体の実装 |
| GradientDescent.scala | `mllib/src/main/scala/org/apache/spark/mllib/optimization/GradientDescent.scala` | ソース | 勾配降下法オプティマイザ |
| Gradient.scala | `mllib/src/main/scala/org/apache/spark/mllib/optimization/Gradient.scala` | ソース | 勾配の基底クラス |
