R dplyr データ整形パイプライン: 生データからクリーンなテーブルへ
問題
アナリストは、データセットをクレンジングするたびに、同じような R のループを何度も書き直して時間を失ってしまいます。その結果、壊れやすいスクリプト、不整合な列、そして新しいファイルが届くたびに遅い反復作業が発生します。
揺さぶり(Agitate)
手作業のステップが積み重なります: 間違った列を選択する、処理の順序を誤る、factor と character の扱いを忘れる、などです。ミスのたびに再実行が必要になり、そのたびにダッシュボードなど下流へ誤った指標を流してしまうリスクが生じます。
解決策
SQL のロジックをなぞりつつ、すべての変換処理を読みやすく保てる一貫した dplyr パイプラインを採用します。以下の動詞だけで、列の選択、行のフィルタリング、新しい特徴量の作成、要約統計、並べ替え、安全な結合をカバーし、モデリングや可視化の前にデータを整然(tidy)な状態にできます。
コアパイプラインの例
library(dplyr)
clean_sales <- raw_sales %>%
mutate(
region = as.character(region), # avoid accidental factor levels
revenue = price * quantity
) %>%
filter(!is.na(revenue), revenue > 0) %>%
select(order_id, region, revenue, channel, order_date) %>%
arrange(desc(revenue)) %>%
group_by(region, channel) %>%
summarise(
orders = n(),
revenue = sum(revenue),
avg_order = mean(revenue),
.groups = "drop"
)dplyr の動詞と SQL の対応
| dplyr verb | 目的 | SQL における類似構文 | 補足メモ |
|---|---|---|---|
select() | 列の選択・リネーム | SELECT col1, col2 | everything() を使うと一括で並べ替え可能。 |
filter() | 行の抽出 | WHERE condition | 複数値には %in% を組み合わせる。 |
mutate() | 列の追加・変換 | SELECT col1, col2*2 AS col2x | 型を安定させるには if_else() を優先。 |
summarise() + group_by() | グループ集計 | GROUP BY ... | 終わりに .groups = "drop" を付けて ungroup。 |
arrange() | 行の並べ替え | ORDER BY | 降順には desc() を使用。 |
left_join() | 参照テーブルで列を付加 | LEFT JOIN | 結合キーの型(character vs factor)を揃える。 |
bind_rows() / bind_cols() | テーブルの縦結合・横結合 | UNION ALL / 列の連結 | 縦に積むときはスキーマを揃える。 |
Join と bind の違い(ざっくり)
# Join: 参照テーブルから列を付加
sales_with_regions <- sales %>%
left_join(region_lookup, by = "region_id")
# Bind: 同じスキーマのテーブルを縦に積む
all_sales <- bind_rows(sales_2023, sales_2024)factor とエンコーディングの落とし穴を避ける
- 結合前に ID 系の列は
characterに変換して、レベルの不一致によるミスマッチを防ぐ。 - CSV 読み込みで暗黙に
factorになっている場合は、mutate(across(where(is.factor), as.character))を使って一括変換する。 - 集計や
group_by()の前に、stringr::str_trimやtolowerでテキストを正規化し、重複カテゴリ(表記揺れ)を避ける。
クイックスタート用テンプレート
prep_data <- function(df) {
df %>%
mutate(across(where(is.factor), as.character)) %>%
filter(!is.na(key_id)) %>%
distinct() %>%
select(key_id, everything())
}保存前のチェックリスト
- 列は明示的に選択され、順序も意図どおりに並んでいる。
- 重要な
joinでは、キーの型が揃っており、必要ならわかりやすいサフィックス(suffix = c(".src", ".lkp"))を付けている。 - 集計後はグループを解除しており、後続ステップでの予期せぬグルーピングを防げている。
- 出力テーブルは、プロットやモデル投入にそのまま使えるクリーンで読みやすい列だけを含んでいる。
関連ガイド
- ゼロから tidy なテーブルを作る: Creating Dataframe in R
- 集計のためのグルーピング: Grouping in R with group_by()
- 可視化前の下ごしらえ: R ggplot2 Quickstart