# 機能設計書 21-add_tally

## 概要

本ドキュメントは、dplyrパッケージにおける`add_tally`関数の機能設計を定義する。`add_tally`は、データフレームの各グループ内の観測数を集計し、新しい列として追加するユーティリティ関数である。

### 本機能の処理概要

`add_tally`関数は、グループ化されたデータフレームに対して、各グループ内の行数（またはウェイト付き合計）を計算し、その結果を新しい列として元のデータフレームに追加する関数である。`summarise`ではなく`mutate`を使用するため、元のデータ構造を保持しながら集計情報を付加できる点が特徴である。

**業務上の目的・背景**：データ分析において、グループごとの出現頻度を把握しながら、個々のレコードの詳細情報も維持したいケースは頻繁に発生する。例えば、顧客ごとの購入回数を各購入レコードに付与したい場合や、カテゴリ別の商品数を各商品レコードに追加したい場合などである。`add_tally`は、この要求を簡潔に実現するための関数として設計されている。従来は`group_by() |> mutate(n = n()) |> ungroup()`という複数ステップが必要だった処理を1関数で実行可能にする。

**機能の利用シーン**：
- グループごとのカウント情報を各レコードに付与したデータセットを作成する場合
- 全体に占める割合の計算の前処理として、総数を各行に追加する場合
- ウェイト付き集計（売上金額の合計など）を各レコードに付与する場合
- `add_count`関数の低レベル版として、グループ化済みデータに対して集計を追加する場合

**主要な処理内容**：
1. 入力データフレームの変数名を取得し、カウント列名の重複をチェック
2. ウェイト引数が指定されていれば`sum(wt)`、なければ`n()`を使用する集計式を構築
3. `mutate`関数を使用して集計結果を新しい列として追加
4. `sort = TRUE`の場合、結果を降順でソート
5. 元のデータフレーム構造を保持したまま結果を返却

**関連システム・外部連携**：dplyrパッケージ内の`mutate`、`n()`、`arrange`、`desc`関数と連携して動作する。rlangパッケージのquosure操作を使用してNSE（Non-Standard Evaluation）を実現している。

**権限による制御**：特になし。Rの通常のオブジェクト操作権限に依存する。

## 関連画面

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

## 機能種別

計算処理 / データ変換

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| x | data.frame / tibble / grouped_df | Yes | 集計対象のデータフレーム | data.frameまたはその拡張型であること |
| wt | quosure（列参照） | No | ウェイト列。指定時はsum(wt)で集計 | NULL、または評価可能な列参照 |
| sort | logical | No | TRUEの場合、結果を降順ソート | TRUE/FALSE |
| name | character | No | 追加する列の名前（デフォルト: "n"） | NULL、または長さ1の文字列 |

### 入力データソース

R環境内のdata.frame、tibble、またはgrouped_dfオブジェクト

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| result | data.frame / tibble | 入力と同じ型で、集計列が追加されたデータフレーム |
| {name} | integer / numeric | グループ内の行数（wt指定時はウェイトの合計） |

### 出力先

R環境内のオブジェクトとして返却

## 処理フロー

### 処理シーケンス

```
1. 引数の検証と前処理
   └─ check_n_name: name引数のバリデーションと自動命名
2. エラーハンドリング設定
   └─ dplyr_local_error_call: エラーコールフレームの設定
3. ウェイト引数の処理
   └─ compat_wt: quosureの互換性処理
4. 集計式の構築
   └─ tally_n: n()またはsum(wt)の式を生成
5. mutateによる列追加
   └─ mutate(x, !!name := !!n)
6. 必要に応じてソート
   └─ sort=TRUEの場合: arrange(out, desc(!!sym(name)))
7. 結果の返却
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[check_n_name: 列名検証]
    B --> C{列名が既存?}
    C -->|Yes| D[代替名生成 n→nn→nnn...]
    C -->|No| E[指定名を使用]
    D --> F[dplyr_local_error_call設定]
    E --> F
    F --> G[compat_wt: wt引数処理]
    G --> H[tally_n: 集計式構築]
    H --> I{wt指定?}
    I -->|Yes| J[sum(wt, na.rm=TRUE)]
    I -->|No| K[n()]
    J --> L[mutate実行]
    K --> L
    L --> M{sort=TRUE?}
    M -->|Yes| N[arrange降順ソート]
    M -->|No| O[結果返却]
    N --> O
    O --> P[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-21-01 | 列名自動生成 | 指定列名が既存の場合、"n"を追加して一意化 | name=NULLまたは重複時 |
| BR-21-02 | ウェイト集計 | wt指定時はsum(wt, na.rm=TRUE)を使用 | wt引数が非NULL時 |
| BR-21-03 | グループ保持 | 入力のグループ化状態を維持 | 常に適用 |
| BR-21-04 | 型保持 | 入力と同じデータフレーム型を返却 | 常に適用 |

### 計算ロジック

- **行数カウント（wt未指定時）**: `n()` を使用してグループ内の行数を計算
- **ウェイト付き集計（wt指定時）**: `sum(wt, na.rm = TRUE)` を使用してウェイト列の合計を計算

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

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

本機能はインメモリ処理のため、データベース操作は発生しない。ただし、dbplyrバックエンドと連携した場合、SQLクエリが生成される。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | check_string | name引数が長さ1の文字列でない | 正しい形式のname引数を指定 |
| - | tally_n | wt引数の評価に失敗 | 有効な列参照を指定 |

### リトライ仕様

該当なし（同期処理）

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

該当なし（インメモリ処理）

## パフォーマンス要件

- 計算量: O(n)（nはデータフレームの行数）
- グループ化されている場合、グループ数に比例した処理時間

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

特になし。入力データの機密性は呼び出し側の責任で管理する。

## 備考

- `add_count`との違い: `add_count`はグループ化変数を引数で指定するが、`add_tally`は既存のグループ化を使用する
- 非推奨警告: `wt = n()`の指定は1.0.1以降非推奨となり、wtを省略することが推奨される

---

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

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

### 推奨読解順序

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

まず、add_tally関数がどのような引数を受け取り、どのような出力を生成するかを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | count-tally.R | `R/count-tally.R` | add_tally関数のシグネチャとドキュメントを確認 |

**読解のコツ**: roxygen2コメントの`@param`と`@return`セクションで引数と戻り値の仕様を把握する。

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

add_tally関数の実装を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | count-tally.R | `R/count-tally.R` | add_tally関数本体（219-233行目） |

**主要処理フロー**:
1. **219行目**: 関数定義の開始 - `add_tally <- function(x, wt = NULL, sort = FALSE, name = NULL)`
2. **220行目**: `check_n_name` - 列名の検証と自動命名処理
3. **222行目**: `dplyr_local_error_call` - エラーハンドリング設定
4. **224行目**: `compat_wt` - ウェイト引数のquosure変換と互換性処理
5. **225行目**: `tally_n` - 集計式の動的構築
6. **226行目**: `mutate` - 実際の列追加処理
7. **228-232行目**: ソート処理の条件分岐

#### Step 3: ヘルパー関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | count-tally.R | `R/count-tally.R` | tally_n関数（237-243行目）- 集計式の構築 |
| 3-2 | count-tally.R | `R/count-tally.R` | compat_wt関数（245-262行目）- wt引数の互換性処理 |
| 3-3 | count-tally.R | `R/count-tally.R` | check_n_name関数（264-284行目）- 列名検証 |
| 3-4 | count-tally.R | `R/count-tally.R` | n_name関数（286-293行目）- 一意な列名生成 |

**主要処理フロー**:
- **237-243行目**: tally_n - wtがNULLなら`n()`、そうでなければ`sum(wt, na.rm=TRUE)`を返す
- **245-262行目**: compat_wt - `wt = n()`の非推奨警告を処理
- **264-284行目**: check_n_name - 列名の重複チェックと自動命名
- **286-293行目**: n_name - "n"が存在すれば"nn"、それも存在すれば"nnn"...と一意化

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

```
add_tally(x, wt, sort, name)
    │
    ├─ check_n_name(name, vars)
    │      └─ n_name(vars) - 列名が重複する場合
    │
    ├─ dplyr_local_error_call()
    │
    ├─ compat_wt(enquo(wt))
    │      └─ lifecycle::deprecate_warn() - wt=n()の場合
    │
    ├─ tally_n(x, wt)
    │      └─ expr(dplyr::n()) または expr(base::sum(!!wt, na.rm=TRUE))
    │
    ├─ mutate(x, !!name := !!n)
    │
    └─ arrange(out, desc(!!sym(name))) - sort=TRUEの場合
```

### データフロー図

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

data.frame/tibble ─────┬──────────────────────────────────────────────────────▶ 拡張されたdata.frame
                       │
                       ├─▶ check_n_name() ─▶ 列名決定
                       │
                       ├─▶ compat_wt() ─▶ wt quosure
                       │
                       ├─▶ tally_n() ─▶ 集計式(n() or sum())
                       │
                       └─▶ mutate() ─▶ 列追加
                              │
                              └─▶ arrange() ─▶ [sort=TRUE時のみ]
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| count-tally.R | `R/count-tally.R` | ソース | count, tally, add_count, add_tally関数の定義 |
| mutate.R | `R/mutate.R` | ソース | mutate関数の実装（add_tallyが内部で使用） |
| arrange.R | `R/arrange.R` | ソース | arrange関数の実装（sort=TRUE時に使用） |
| desc.R | `R/desc.R` | ソース | desc関数の実装（降順ソートに使用） |
| context.R | `R/context.R` | ソース | n()関数の実装 |
