# 機能設計書 50-lag

## 概要

本ドキュメントは、dplyrパッケージの`lag()`関数の機能設計について記述する。`lag()`はベクトルのラグ値（前の値）を取得する関数であり、時系列データ分析で広く使用される。

### 本機能の処理概要

`lag()`は、ベクトルの各要素を指定した位置数だけ後ろにシフトし、先頭には`NA`または指定したデフォルト値を挿入する関数である。これにより、現在の値と前の値を比較したり、差分を計算したりすることが容易になる。対になる関数として`lead()`（次の値を取得）がある。

**業務上の目的・背景**：時系列データ分析では、前の期間の値と現在の値を比較することが頻繁に発生する。例えば、前月比、前年同期比、移動平均の計算などである。`lag()`はこのような操作を簡潔に記述でき、`mutate()`内で使用することで効率的な時系列計算が可能になる。

**機能の利用シーン**：
- 前日/前月/前年との比較（変化率、差分の計算）
- 移動平均の計算
- 連続した値間の変化の検出
- 時系列データのウィンドウ操作

**主要な処理内容**：
1. 入力ベクトルを指定した位置数だけシフトする
2. 先頭に`NA`または指定したデフォルト値を挿入する
3. `order_by`が指定されている場合は、その順序に従ってシフトする
4. 結果ベクトルを返す

**関連システム・外部連携**：vctrsパッケージの各種関数を使用する。

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | 該当なし | - | 本プロジェクトはRライブラリであり、ユーザーインターフェース画面は存在しない |

## 機能種別

計算処理 / データ変換 / 時系列操作

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| x | any | Yes | シフト対象のベクトル | ベクトルであること。ts型は不可 |
| n | integer | No | シフトする位置数（デフォルト: 1） | 正の整数であること |
| default | any | No | 先頭に挿入する値（デフォルト: NULL = NA） | サイズ1でxの型にキャスト可能であること |
| order_by | any | No | シフトの順序を定義するベクトル | xと同じサイズであること |
| ... | - | No | 未使用 | 空であること |

### 入力データソース

関数の引数として直接渡されるベクトル

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| result | any | xと同じサイズ、同じ型を持つベクトル。先頭n個の要素はNA（またはdefault）に置換される |

### 出力先

呼び出し元に返される。

## 処理フロー

### 処理シーケンス

```
1. 入力の検証
   └─ xがts型でないことを確認（ts型の場合はstats::lag()を使用するようエラー）
   └─ ...が空であることを確認
   └─ nが正の整数であることを確認
2. order_byの処理
   └─ order_byが指定されている場合はwith_order()を呼び出す
3. shift()関数の呼び出し
   └─ nが正（lag）または負（lead）に応じて処理
4. シフト処理
   └─ defaultがNULLの場合はshift_slice()でNA挿入
   └─ defaultが指定されている場合はshift_c()でdefault挿入
5. 結果ベクトルを返す
```

### フローチャート

```mermaid
flowchart TD
    A[開始: lag呼び出し] --> B{xがts型か?}
    B -->|Yes| C[エラー: stats::lag を使用してください]
    B -->|No| D{nが正か?}
    D -->|No| E[エラー: n must be positive]
    D -->|Yes| F{order_byが指定されているか?}
    F -->|Yes| G[with_order でorder_byの順序で処理]
    F -->|No| H[shift 関数を呼び出し]
    G --> H
    H --> I{defaultがNULLか?}
    I -->|Yes| J[shift_slice でNA挿入]
    I -->|No| K[shift_c でdefault挿入]
    J --> L[結果ベクトルを返す]
    K --> L
    C --> M[終了]
    E --> M
    L --> M
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-50-01 | 型安定性 | 出力はxと同じ型 | 常に適用 |
| BR-50-02 | サイズ安定性 | 出力はxと同じサイズ | 常に適用 |
| BR-50-03 | ts型禁止 | ts型の入力は禁止。stats::lag()を使用すること | xがts型の場合 |
| BR-50-04 | 正のn | nは正の整数でなければならない | 常に適用 |
| BR-50-05 | n超過時 | nがxのサイズを超える場合はサイズに制限される | n > length(x)の場合 |
| BR-50-06 | default制約 | defaultはサイズ1でxの型にキャスト可能であること | defaultが指定された場合 |

### 計算ロジック

```
# lag (n > 0)の場合
result[1:n] = NA (or default)
result[(n+1):size] = x[1:(size-n)]

# 例: lag(c(1, 2, 3, 4, 5), n = 2)
# result = c(NA, NA, 1, 2, 3)
```

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| - | - | - | 本関数はインメモリ操作のみでデータベース操作を行わない |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 型エラー | xがts型の場合 | stats::lag()を使用する |
| - | 引数エラー | nが負の場合 | 正のnを指定する（負の場合はlead()を使用） |
| - | 引数エラー | nが整数でない場合 | 整数を指定する |
| - | サイズエラー | defaultのサイズが1でない場合 | サイズ1の値を指定する |

### リトライ仕様

リトライは不要（即座にエラーを返す）

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

該当なし（インメモリ操作のみ）

## パフォーマンス要件

- vctrsの効率的な実装を活用すること
- 大規模ベクトルでも効率的に動作すること

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

特になし

## 備考

- `lag()`と`lead()`は対になる関数
- `stats::lag()`とは異なる動作をするため注意（dplyrの`lag()`はts型を受け付けない）
- `order_by`引数でソート順序を指定できる（データがソートされていない場合に有用）
- グループ化されたデータでは、グループ内でラグが計算される

---

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

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

### 推奨読解順序

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

`lag()`は内部で`shift()`関数を使用してシフト処理を行う。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | lead-lag.R | `R/lead-lag.R` | `lag()`と`lead()`関数の全体構造を理解する |

**読解のコツ**: `lag()`と`lead()`は共通の`shift()`関数を使用している。`lag`は正のn、`lead`は負のnとして処理される。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | lead-lag.R | `R/lead-lag.R` | 58-70行目の`lag()`関数定義 |

**主要処理フロー**:
1. **59-61行目**: ts型チェック - ts型の場合はエラー
2. **62行目**: `check_dots_empty0()` - ...引数が空であることを確認
3. **64-67行目**: nの検証 - 正の整数であることを確認
4. **69行目**: `shift()`を呼び出し

#### Step 3: shift()関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | lead-lag.R | `R/lead-lag.R` | 85-138行目の`shift()`関数 |

**主要処理フロー**:
- **95-105行目**: `order_by`が指定されている場合の処理
- **107行目**: `obj_check_vector()` - xがベクトルであることを確認
- **112-122行目**: `default`の検証とキャスト
- **124-125行目**: lagかleadかの判定
- **133-137行目**: `shift_slice()`または`shift_c()`の呼び出し

#### Step 4: シフト実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | lead-lag.R | `R/lead-lag.R` | 140-166行目の`shift_slice()`と`shift_c()`関数 |

**読解のコツ**: `shift_slice()`はNAを挿入する場合、`shift_c()`はdefaultを挿入する場合に使用される。

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

```
lag(x, n, default, order_by)
    │
    ├─ ts型チェック [ts型の場合はエラー]
    │
    ├─ check_dots_empty0(...) [引数検証]
    │
    ├─ check_number_whole(n) [nの検証]
    │
    └─ shift(x, n, default, order_by)
           │
           ├─ with_order() [order_byが指定されている場合]
           │
           ├─ obj_check_vector(x) [ベクトル検証]
           │
           ├─ vec_cast(default, x) [defaultのキャスト]
           │
           └─ shift_slice() or shift_c()
                  ├─ vec_slice() [シフト処理]
                  └─ vec_c() [結合処理]
```

### データフロー図

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

x (ベクトル)       ───▶  shift()でシフト処理        ───▶  シフト済みベクトル

n (シフト量)       ───▶  正負判定でlag/lead決定     ───▶  シフト方向

default            ───▶  vec_cast()でxの型にキャスト ───▶  挿入値

order_by           ───▶  with_order()で順序指定     ───▶  順序付きシフト
  (オプション)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| lead-lag.R | `R/lead-lag.R` | ソース | `lag()`、`lead()`、`shift()`関数の実装 |
| order-by.R | `R/order-by.R` | ソース | `with_order()`関数（順序指定シフト） |
