# 機能設計書 48-na_if

## 概要

本ドキュメントは、dplyrパッケージの`na_if()`関数の機能設計について記述する。`na_if()`は特定の値を`NA`に置換する関数であり、SQLのNULLIF関数に相当する。

### 本機能の処理概要

`na_if()`は、ベクトル`x`の各要素を値`y`と比較し、等しい場合は`NA`に、そうでない場合は元の値を返す関数である。これはSQLの`NULLIF`関数のR言語版であり、特定の問題のある値（例：空文字列、-99などのセンチネル値）を`NA`に変換するために使用される。出力は`x`と同じ型とサイズを持つ（型安定性）。

**業務上の目的・背景**：データ分析において、欠損値を表すために`NA`以外の特殊な値（センチネル値）が使用されることがある。例えば、-99、999、空文字列、"unknown"などである。これらの値を分析の前に適切な`NA`に変換することで、後続の処理（平均値計算など）で正しい結果が得られるようになる。`na_if()`はこの変換を簡潔に記述できる。

**機能の利用シーン**：
- センチネル値（例：-99, 999）を`NA`に変換する
- 空文字列を`NA`に変換する
- `NaN`を`NA`に標準化する
- 特定の値を欠損として扱う

**主要な処理内容**：
1. `y`を`x`の型にキャストする
2. `y`を`x`のサイズにリサイクルする
3. `x`と`y`を要素ごとに比較する
4. 等しい要素を`NA`に置換する
5. 結果ベクトルを返す

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

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

## 関連画面

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

## 機能種別

計算処理 / データ変換 / 欠損値処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| x | any | Yes | 変換対象のベクトル | ベクトルであること |
| y | any | Yes | `NA`に置換する値。xと等しい要素が`NA`になる | xの型にキャスト可能であること |

### 入力データソース

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

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| result | any | xと同じサイズ、同じ型を持つベクトル。yと等しい要素はNAに置換される |

### 出力先

呼び出し元に返される。

## 処理フロー

### 処理シーケンス

```
1. 型変換
   └─ vec_cast()でyをxの型にキャスト
2. サイズ調整
   └─ vec_recycle()でyをxのサイズにリサイクル
3. 比較と置換
   └─ vec_init()でNA値を作成
   └─ vec_equal()でxとyを比較（na_equal = TRUE）
   └─ vec_assign()で等しい位置をNAに置換
4. 結果ベクトルを返す
```

### フローチャート

```mermaid
flowchart TD
    A[開始: na_if呼び出し] --> B[yをxの型にキャスト]
    B --> C[yをxのサイズにリサイクル]
    C --> D[xの型のNA値を作成]
    D --> E[vec_equal でxとyを比較]
    E --> F{x[i] == y[i]?}
    F -->|Yes| G[x[i]をNAに置換]
    F -->|No| H[x[i]を保持]
    G --> I[結果ベクトルを返す]
    H --> I
    I --> J[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-48-01 | 型安定性 | 出力はxと同じ型 | 常に適用 |
| BR-48-02 | サイズ安定性 | 出力はxと同じサイズ | 常に適用 |
| BR-48-03 | 要素ごと比較 | xとyは要素ごとに比較される | yがベクトルの場合 |
| BR-48-04 | NA等価比較 | NAとNAは等しいとみなされる（na_equal = TRUE） | 常に適用 |

### 計算ロジック

```
y <- vec_cast(y, x)
y <- vec_recycle(y, length(x))
na <- vec_init(x)  # xの型のNA
where <- vec_equal(x, y, na_equal = TRUE)
x[where] <- na
return(x)
```

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

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 型エラー | yがxの型にキャストできない場合 | 互換性のある値を使用する |
| - | サイズエラー | yがxのサイズにリサイクルできない場合 | スカラーまたはxと同じサイズのベクトルを使用する |

### リトライ仕様

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

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

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

## パフォーマンス要件

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

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

特になし

## 備考

- `na_if()`はSQLの`NULLIF`のR版
- 複数の値を`NA`に変換する場合は`replace_values(x, c(val1, val2) ~ NA)`を使用する
- `NA`を別の値に置換する場合は`coalesce()`または`replace_values()`を使用する
- `na_if()`をネストするよりも`replace_values()`を使用する方が効率的

---

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

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

### 推奨読解順序

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

`na_if()`は非常にシンプルな関数で、vctrsの基本関数を組み合わせて実装されている。

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

**読解のコツ**: わずか12行の実装であり、vctrsの`vec_cast()`, `vec_recycle()`, `vec_init()`, `vec_equal()`, `vec_assign()`を組み合わせている。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | na-if.R | `R/na-if.R` | 71-82行目の`na_if()`関数定義 |

**主要処理フロー**:
1. **73行目**: `vec_cast()`でyをxの型にキャスト
2. **74行目**: `vec_recycle()`でyをxのサイズにリサイクル
3. **76行目**: `vec_init()`でNA値を作成
4. **77行目**: `vec_equal()`でxとyを比較（na_equal = TRUE）
5. **79行目**: `vec_assign()`でwhereの位置をNAに置換
6. **81行目**: 結果を返す

#### Step 3: ドキュメントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | na-if.R | `R/na-if.R` | 1-70行目のroxygenドキュメント |

**読解のコツ**: ドキュメントには`replace_values()`との比較、複数値のNA変換方法、`coalesce()`との関係が記載されている。

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

```
na_if(x, y)
    │
    ├─ vec_cast(y, to = x)
    │      └─ yをxの型にキャスト
    │
    ├─ vec_recycle(y, size = length(x))
    │      └─ yをxのサイズにリサイクル
    │
    ├─ vec_init(x)
    │      └─ xの型のNA値を作成
    │
    ├─ vec_equal(x, y, na_equal = TRUE)
    │      └─ xとyを要素ごとに比較
    │
    └─ vec_assign(x, where, na)
           └─ whereの位置をNAに置換
```

### データフロー図

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

x (ベクトル)       ───▶  型とサイズの基準として使用  ───▶  x

y (値)             ───▶  vec_cast()でxの型にキャスト ───▶  キャスト済みy

キャスト済みy      ───▶  vec_recycle()でリサイクル   ───▶  リサイクル済みy

x + リサイクル済みy ───▶ vec_equal()で比較           ───▶  where (論理)

x + where + NA     ───▶  vec_assign()で置換          ───▶  結果ベクトル
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| na-if.R | `R/na-if.R` | ソース | `na_if()`関数の実装 |
| coalesce.R | `R/coalesce.R` | ソース | `coalesce()`関数（逆操作） |
| recode-values.R | `R/recode-values.R` | ソース | `replace_values()`関数（複数値のNA変換） |
