Skip to content

R dplyr データ整形パイプライン: 生データからクリーンなテーブルへ

問題

アナリストは、データセットをクレンジングするたびに、同じような R のループを何度も書き直して時間を失ってしまいます。その結果、壊れやすいスクリプト、不整合な列、そして新しいファイルが届くたびに遅い反復作業が発生します。

揺さぶり(Agitate)

手作業のステップが積み重なります: 間違った列を選択する、処理の順序を誤る、factorcharacter の扱いを忘れる、などです。ミスのたびに再実行が必要になり、そのたびにダッシュボードなど下流へ誤った指標を流してしまうリスクが生じます。

解決策

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, col2everything() を使うと一括で並べ替え可能。
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_trimtolower でテキストを正規化し、重複カテゴリ(表記揺れ)を避ける。

クイックスタート用テンプレート

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"))を付けている。
  • 集計後はグループを解除しており、後続ステップでの予期せぬグルーピングを防げている。
  • 出力テーブルは、プロットやモデル投入にそのまま使えるクリーンで読みやすい列だけを含んでいる。

関連ガイド