# 機能設計書 2-filter_out

## 概要

本ドキュメントは、dplyrパッケージの`filter_out`関数に関する機能設計書です。`filter_out`関数は、`filter`関数の逆操作として、論理条件に基づいてデータフレームの行を除外する機能を提供します。

### 本機能の処理概要

`filter_out`関数は、指定された論理条件を評価し、その条件が`TRUE`となる行を**除外**するデータフレーム操作関数です。`filter`関数とは逆に、条件を満たす行が削除され、条件を満たさない行（`FALSE`または`NA`）が保持されます。

**業務上の目的・背景**：データ分析において、「特定のデータを除外したい」という要求は頻繁に発生します。従来の`filter`関数では、除外条件を指定する際に否定演算子（`!`や`!=`）を使用する必要があり、NA値の扱いが直感に反する結果を生むことがありました。`filter_out`関数は、除外の意図を明確に表現でき、NA値も適切に保持されるため、より直感的なコードを書くことができます。

**機能の利用シーン**：
- 外れ値や異常値の除外（例：売上が負の値のデータを除外）
- 特定カテゴリの除外（例：「その他」カテゴリを除外）
- 欠損値を含むレコードの適切な保持（NA値を除外したくない場合）
- 条件に一致する不要データの削除

**主要な処理内容**：
1. 引数のバリデーション（`.by`と`.preserve`の同時指定チェック等）
2. quosureの作成と条件式の展開
3. グループ化情報の計算
4. データマスク環境でのフィルタ条件の評価
5. 条件を満たす行の**反転**インデックスの計算
6. `dplyr_row_slice`による行の抽出

**関連システム・外部連携**：
- tidyselect: 列選択機能との連携
- vctrs: ベクトル操作基盤
- rlang: quosureとデータマスキング機能

**権限による制御**：該当なし（Rライブラリのため）

## 関連画面

本プロジェクトはRライブラリ（dplyr）であり、ユーザーインターフェース画面は存在しません。

## 機能種別

データ操作（行の除外）/ データ変換

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| .data | data.frame | Yes | 処理対象のデータフレーム | data.frameまたはその派生クラス |
| ... | expressions | No | 論理値を返す条件式（複数指定可能） | 論理ベクトルを返す式であること |
| .by | tidy-select | No | 一時的なグループ化に使用する列 | データ内に存在する列であること |
| .preserve | logical | No | グループ構造を保持するか（デフォルト: FALSE） | `.by`と同時指定不可 |

### 入力データソース

- メモリ上のdata.frame、tibble、grouped_df、rowwise_df

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 戻り値 | .dataと同じ型 | 条件に一致する行が除外されたデータフレーム |

### 出力先

- 関数の戻り値として返却（メモリ上）

## 処理フロー

### 処理シーケンス

```
1. 引数バリデーション
   └─ check_by_typo(): ...引数内の.byタイポをチェック
   └─ check_not_both_by_and_preserve(): .byと.preserveの同時指定をチェック
2. ジェネリック関数のディスパッチ
   └─ UseMethod("filter_out")でクラスに応じたメソッドを呼び出し
3. filter_impl()の実行（.verb = "filter_out"として）
   └─ dplyr_quosures()で条件式をquosureに変換
   └─ check_filter()で名前付き引数のバリデーション
   └─ compute_by()でグループ化情報を計算
4. filter_rows()の実行
   └─ DataMask$new()でデータマスクを作成
   └─ filter_expand()で条件式を展開
   └─ filter_eval()で条件を評価（invert=TRUEで反転）
5. dplyr_row_slice()で行を抽出
```

### フローチャート

```mermaid
flowchart TD
    A[filter_out開始] --> B{引数バリデーション}
    B -->|エラー| E1[エラー終了]
    B -->|OK| C[UseMethod dispatch]
    C --> D[filter_out.data.frame]
    D --> F[filter_impl<br>.verb=filter_out]
    F --> G[quosure作成]
    G --> H[グループ化計算]
    H --> I[DataMask作成]
    I --> J[条件式展開]
    J --> K[条件評価<br>invert=TRUE]
    K --> L{条件結果の検証}
    L -->|型エラー| E2[エラー終了]
    L -->|OK| M[行インデックス計算<br>TRUEの行を除外]
    M --> N[dplyr_row_slice]
    N --> O[結果返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | NA値の保持 | NAはFALSEと同様に扱われ、条件がNAの行は保持される | 常時 |
| BR-02 | 複数条件の結合 | カンマ区切りの複数条件は&演算子で結合され、すべてTRUEの行が除外される | 複数条件指定時 |
| BR-03 | グループ内評価 | グループ化されたデータでは条件がグループ内で評価される | grouped_df使用時 |
| BR-04 | 行順序の保持 | 出力行は入力と同じ順序で出現する | 常時 |
| BR-05 | filterとの補完関係 | filter(data, cond) + filter_out(data, cond) = data（全行を網羅） | 常時 |

### 計算ロジック

- 条件式は各行に対してベクトル化評価される
- 条件がTRUEの行は**除外**される
- 条件がFALSEまたはNAの行は**保持**される
- filterとの違い: `invert = TRUE`フラグにより結果が反転

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | dplyr:::filter_incompatible_type | 条件式が論理ベクトル以外を返した場合 | 条件式を論理値を返すよう修正 |
| - | dplyr:::filter_incompatible_size | 条件式の結果サイズが行数と一致しない場合 | 条件式を修正 |
| - | abort | .byと.preserveを同時指定した場合 | どちらか一方のみ指定 |
| - | abort | 名前付き引数で=を==と間違えた場合 | ==演算子を使用 |

### リトライ仕様

該当なし（同期処理のため）

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

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

## パフォーマンス要件

- `filter`関数と同等のパフォーマンス
- 条件評価後の反転処理はC++レベルで実施されるためオーバーヘッドは最小限

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

- `filter`関数と同様

## 備考

- `filter_out`は`filter`と同一の実装（filter_impl）を共有し、`.verb`パラメータで動作を切り替える
- invert変数の値が`filter`と`filter_out`の動作の違いを決定する
- 実装はR/filter.Rの224-228行目で定義

---

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

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

### 推奨読解順序

#### Step 1: filter_outの定義を理解する

まず、filter_out関数がどのように定義されているかを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | filter.R | `R/filter.R` | filter_out関数の定義位置と構造 |

**読解のコツ**: filter_outはfilterと同じファイル内で定義されており、ほぼ同じ構造を持つ。違いは`.verb`パラメータの値のみ。

**主要処理フロー**:
- **224-228行目**: filter_out関数定義
- **242-250行目**: filter_out.data.frame実装

#### Step 2: filterとの違いを理解する

filterとfilter_outの処理の違いを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | filter.R | `R/filter.R` | filter_impl内でのverb引数の使用 |
| 2-2 | filter.R | `R/filter.R` | filter_rows内でのinvert変数 |

**主要処理フロー**:
- **252-283行目**: filter_impl - .verbパラメータを受け取る
- **301行目**: `invert <- verb == "filter_out"` - 反転フラグの設定
- **303-310行目**: filter_eval呼び出し時にinvertを渡す

#### Step 3: 反転処理の実装を理解する

実際の反転処理がどのように行われるかを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | data-mask.R | `R/data-mask.R` | eval_all_filter内での反転処理 |

**主要処理フロー**:
- **120-132行目**: DataMask$eval_all_filter - invertパラメータを受け取る
- C++側（dplyr_mask_eval_all_filter）で実際の反転処理が行われる

#### Step 4: NA値の扱いを理解する

filter_outでNA値が保持される理由を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | filter.R | `R/filter.R` | ドキュメントでのNA値説明 |

**主要処理フロー**:
- **40-50行目**: ドキュメントでのNA値の扱い説明
- filter: NAとFALSEを除外
- filter_out: NAとFALSEを保持（TRUEのみ除外）

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

```
filter_out(.data, ..., .by, .preserve)
    │
    ├─ check_by_typo(...)
    ├─ check_not_both_by_and_preserve(.by, .preserve)
    └─ UseMethod("filter_out")
           │
           └─ filter_out.data.frame(.data, ..., .by, .preserve)
                  │
                  └─ filter_impl(.data, ..., .by, .preserve, .verb="filter_out")
                         │
                         ├─ (filterと同じ処理)
                         └─ filter_rows(data, dots, by, verb="filter_out")
                                │
                                ├─ invert = TRUE  ← filterとの違い
                                └─ filter_eval(dots, dots_expanded, invert=TRUE, mask)
                                       │
                                       └─ mask$eval_all_filter(dots_expanded, invert=TRUE, env_filter)
                                              │
                                              └─ 条件がTRUEの行を除外（FALSEとNAを保持）
```

### データフロー図

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

.data (data.frame)  ───▶ 条件評価 ───▶ 反転処理 ───▶ 行インデックス
                              │              │              │
                              ▼              ▼              ▼
                         TRUE/FALSE/NA   TRUE→除外        loc (integer)
                              │          FALSE/NA→保持        │
                              └──────────────────────────────┘
                                                              │
                                                              ▼
                                                      dplyr_row_slice
                                                              │
                                                              ▼
                                                      結果data.frame
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| filter.R | `R/filter.R` | ソース | filter_out関数の実装（filterと共有） |
| data-mask.R | `R/data-mask.R` | ソース | DataMaskクラス（eval_all_filter） |
| generics.R | `R/generics.R` | ソース | dplyr_row_slice等の汎用関数 |
