dplyr
CHAPTER 02

データ操作マスタリー

dplyrでデータの魔法を体験。filter, select, mutate, summariseを駆使して、複雑なデータ変換をエレガントに実装し、データ分析の生産性を劇的に向上させる。

dplyrとは?

dplyrは「データ操作の文法」を提供するパッケージです。データ分析でよく使われる操作を、人間が理解しやすい「動詞」として表現し、複雑なデータ変換を直感的なコードで記述できます。

dplyrの最大の特徴は、一貫性可読性です。すべての関数が同じ原則に従って設計されているため、一度覚えれば様々な場面で応用できます。

dplyr_setup.R
# dplyrの読み込み(tidyverseに含まれる) library(dplyr) # サンプルデータの作成 sales_data <- tibble( product = c("A", "B", "C", "A", "B"), region = c("East", "West", "East", "West", "East"), sales = c(100, 150, 120, 80, 200), month = c(1, 1, 1, 2, 2) )

データ読み込みの基礎

データ分析の第一歩は、データを適切に読み込むことです。Tidyverseではreadrパッケージとtibbleデータ構造を使って、効率的で安全なデータ読み込みを実現します。

readrによる高速データ読み込み

readrパッケージは、従来のRの読み込み関数よりも高速で、型推論が優秀で、進捗バーも表示される現代的なデータ読み込みツールです。

data_import_examples.R
# 様々な形式のデータ読み込み library(tidyverse) # CSV読み込み(高速&自動型推論) sales_data <- read_csv("sales_2023.csv") # TSV(タブ区切り)ファイル survey_data <- read_tsv("survey_results.tsv") # 区切り文字を指定 custom_data <- read_delim("data.txt", delim = "|") # 固定幅ファイル fixed_data <- read_fwf("fixed_width.txt", fwf_widths(c(10, 15, 8), c("name", "address", "score")) ) # 日本語エンコーディング対応 jp_data <- read_csv("japanese_data.csv", locale = locale(encoding = "CP932"))

tibbleの革新的な特徴

tibbleは従来のdata.frameを現代的に再設計したデータ構造です。より安全で、見やすく、扱いやすくなっています。

🔍 賢い表示

大きなデータでも最初の10行だけ表示し、列の型情報も自動表示。コンソールが溢れません。

🛡️ 型安全性

部分マッチングや予期しない型変換を防ぎ、より予測可能で安全なコードを書けます。

📝 一貫した動作

文字列のファクター自動変換なし、行名なしなど、現代的なデータ分析に適した仕様です。

🚀 高性能

メモリ効率が良く、大きなデータセットでも高速に動作します。

tibble_features.R
# tibbleの作成と特徴 my_tibble <- tibble( id = 1:1000, name = paste0("User_", id), score = rnorm(1000, mean = 75, sd = 15), category = sample(c("A", "B", "C"), 1000, replace = TRUE) ) # tibbleの表示(自動で最初の10行のみ) my_tibble # A tibble: 1,000 × 4 # id name score category # <int> <chr> <dbl> <chr> # 1 1 User_1 78.2 B # 2 2 User_2 82.1 A # ... with 990 more rows # data.frameからtibbleに変換 cars_tibble <- as_tibble(mtcars)

データの基本情報確認

読み込んだデータの構造を理解することは、分析の成功の鍵です。Tidyverseでは効率的なデータ探索ツールが豊富に用意されています。

data_exploration.R
# 基本的なデータ確認 glimpse(my_tibble) # データ構造の簡潔な表示 Rows: 1,000 Columns: 4 $ id <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ... $ name <chr> "User_1", "User_2", "User_3", ... $ score <dbl> 78.2, 82.1, 71.5, 79.8, ... $ category <chr> "B", "A", "C", "A", ... # より詳細な統計サマリー(skimrパッケージ) library(skimr) skim(my_tibble) # 基本統計 summary(my_tibble) # データの次元 dim(my_tibble) # 行数と列数 nrow(my_tibble) # 行数 ncol(my_tibble) # 列数 names(my_tibble) # 列名

日本語データとエンコーディング

日本語データを扱う際は、文字エンコーディングの設定が重要です。readrパッケージは様々なエンコーディングに対応し、日本語データを安全に読み込めます。

japanese_encoding.R
# 日本語エンコーディング対応 # Shift_JIS(Windows標準) sjis_data <- read_csv( "japanese_data.csv", locale = locale(encoding = "CP932") # Windows Shift_JIS ) # UTF-8(現代標準) utf8_data <- read_csv( "modern_data.csv", locale = locale(encoding = "UTF-8") ) # エンコーディング自動検出 guess_encoding("mystery_data.csv") # 日本語ロケール設定 jp_locale <- locale( encoding = "CP932", decimal_mark = ".", # 小数点 grouping_mark = ",", # 桁区切り date_format = "%Y/%m/%d" # 日付形式 ) jp_data <- read_csv("sales_japan.csv", locale = jp_locale)

適切なデータ読み込みは、信頼性の高い分析の基盤です。readrとtibbleを活用することで、効率的で安全なデータ処理ワークフローを構築できます。

5つのコア動詞

dplyrは5つの主要な動詞でデータ操作の大部分をカバーします。各動詞は特定の操作に特化し、組み合わせることで複雑な処理を表現できます。

filter()

条件に合致する行だけを抽出します。WHERE句のようなデータの絞り込みを行います。

filter(data, condition)

select()

必要な列だけを選択します。データセットから特定の変数を取り出したり、列の順序を変更できます。

select(data, columns)

mutate()

新しい列を作成したり、既存の列を変更します。計算フィールドの追加に使用します。

mutate(data, new_col = expression)

summarise()

データを集約して要約統計を計算します。平均、合計、最大値などを求められます。

summarise(data, stat = function(column))
dplyr_verbs_examples.R
# 1. filter() - 東部地域のデータのみ抽出 east_sales <- filter(sales_data, region == "East") # 2. select() - 商品と売上のみ選択 product_sales <- select(sales_data, product, sales) # 3. mutate() - 売上カテゴリを追加 categorized <- mutate(sales_data, category = ifelse(sales >= 150, "High", "Low") ) # 4. summarise() - 地域別の平均売上 region_summary <- sales_data %>% group_by(region) %>% summarise(avg_sales = mean(sales))

パイプ演算子の魔法

パイプ演算子 %>% は、dplyrの真価を発揮させる重要な要素です。複数の操作を左から右へ、上から下へと自然な流れで記述できます。

パイプを使うことで、「データに何をするか」を順序立てて表現でき、コードが読みやすく、理解しやすくなります。

pipe_comparison.R
# パイプを使わない場合(読みにくい) result1 <- summarise( group_by( filter(sales_data, sales > 100), region ), avg_sales = mean(sales) ) # パイプを使う場合(読みやすい) result2 <- sales_data %>% filter(sales > 100) %>% group_by(region) %>% summarise(avg_sales = mean(sales))

パイプを使ったコードは、まるで「レシピ」のように読むことができます:

  1. sales_dataを取って
  2. 売上が100を超えるものだけフィルターして
  3. 地域でグループ化して
  4. 平均売上を計算する

実践的な応用例

実際のデータ分析では、複数の動詞を組み合わせて複雑な処理を行います。以下に典型的なパターンを示します。

advanced_dplyr.R
# より複雑なサンプルデータ employee_data <- tibble( name = c("Alice", "Bob", "Charlie", "Diana", "Eva"), department = c("Sales", "IT", "Sales", "IT", "HR"), salary = c(50000, 70000, 55000, 75000, 60000), experience = c(3, 5, 2, 7, 4) ) # 複合的な分析例 analysis_result <- employee_data %>% # 経験年数3年以上の従業員のみ filter(experience >= 3) %>% # 時給を計算(年間2000時間勤務と仮定) mutate( hourly_rate = salary / 2000, seniority = case_when( experience >= 7 ~ "Senior", experience >= 3 ~ "Mid-level", TRUE ~ "Junior" ) ) %>% # 部署ごとにグループ化 group_by(department, seniority) %>% # 統計サマリーを計算 summarise( count = n(), avg_salary = mean(salary), max_salary = max(salary), avg_experience = mean(experience), .groups = "drop" ) %>% # 平均給与の降順でソート arrange(desc(avg_salary))

このようにdplyrを使うことで、複雑なデータ変換も段階的に、理解しやすい形で記述できます。各ステップが明確で、後から読み返したときも処理の流れが分かりやすくなります。

🚀 高度なdplyr技法と統計前処理

基本的なdplyr操作を習得したら、より高度な技法を学習しましょう。 特に統計分析や機械学習に向けたデータ前処理は、分析の成否を大きく左右します。

📊 時系列データの高度な操作

ビジネス分析では時系列データの処理が頻繁に必要になります。dplyrとslider、lubridateパッケージを組み合わせて効率的に処理しましょう。

time_series_advanced.R
# 時系列データの高度な処理
library(tidyverse)
library(slider)
library(lubridate)

sales_data <- tibble(
  date = seq(ymd("2020-01-01"), ymd("2023-12-31"), by = "day"),
  sales = runif(length(date), 1000, 5000)
)

# 移動平均とトレンド分析
sales_processed <- sales_data %>%
  mutate(
    year = year(date),
    month = month(date),
    weekday = wday(date, label = TRUE),
    
    # 移動平均(7日、30日)
    ma_7 = slide_dbl(sales, mean, .before = 6, .complete = TRUE),
    ma_30 = slide_dbl(sales, mean, .before = 29, .complete = TRUE),
    
    # 前年同期比較
    yoy_growth = (sales - lag(sales, 365)) / lag(sales, 365) * 100,
    
    # 季節調整(月平均との比較)
    monthly_avg = ave(sales, year, month, FUN = mean),
    seasonal_adj = sales / monthly_avg,
    
    # 異常値検出(統計的手法)
    z_score = abs((sales - mean(sales)) / sd(sales)),
    is_outlier = z_score > 2.5,
    
    # トレンド分解
    detrended = sales - ma_30
  ) %>%
  # 欠損値の処理
  fill(ma_7, ma_30, .direction = "down")

🔬 統計的データ変換

機械学習モデルの性能向上のため、データの正規化・標準化・特徴量エンジニアリングを実践しましょう。

statistical_preprocessing.R
# 統計的データ前処理のベストプラクティス
library(tidyverse)

# サンプルデータ
customer_data <- tibble(
  customer_id = 1:1000,
  age = rnorm(1000, 35, 10),
  income = rlnorm(1000, 10.5, 0.5),
  purchase_count = rpois(1000, 5),
  category = sample(c("A", "B", "C"), 1000, replace = TRUE)
)

# 統計的変換の実践
processed_data <- customer_data %>%
  mutate(
    # 1. 正規化(Min-Max スケーリング)
    age_normalized = (age - min(age)) / (max(age) - min(age)),
    
    # 2. 標準化(Z-score)
    income_standardized = (income - mean(income)) / sd(income),
    
    # 3. 対数変換(歪んだ分布の修正)
    income_log = log(income),
    
    # 4. 四分位区間によるロバストスケーリング
    age_robust = (age - median(age)) / IQR(age),
    
    # 5. カテゴリカル変数のエンコーディング
    # ワンホットエンコーディング
    category_A = as.numeric(category == "A"),
    category_B = as.numeric(category == "B"),
    category_C = as.numeric(category == "C"),
    
    # 6. 特徴量エンジニアリング
    # 購入頻度カテゴリ
    purchase_frequency = case_when(
      purchase_count <= 2 ~ "Low",
      purchase_count <= 5 ~ "Medium",
      TRUE ~ "High"
    ),
    
    # 収入年齢比
    income_age_ratio = income / age,
    
    # 7. ビニング(連続値の離散化)
    age_group = cut(age, 
                   breaks = c(0, 25, 35, 50, 100),
                   labels = c("Young", "Adult", "Middle", "Senior"),
                   include.lowest = TRUE),
    
    # 8. 異常値の処理(Winsorization)
    income_winsorized = pmax(pmin(income, 
                                  quantile(income, 0.95, na.rm = TRUE)),
                             quantile(income, 0.05, na.rm = TRUE))
  )

🧠 高度なdplyrパターン

advanced_dplyr_patterns.R
# プロフェッショナルなdplyrパターン

# 1. 条件付き変換のエレガントな方法
data %>%
  mutate(
    new_column = case_when(
      condition1 ~ value1,
      condition2 ~ value2,
      condition3 ~ value3,
      TRUE ~ default_value  # else句
    )
  )

# 2. 複数列に対する同じ処理
data %>%
  mutate(across(where(is.numeric), ~ scale(.)[,1]))  # 数値列を標準化

# 3. 動的な列選択
columns_to_analyze <- c("sales", "profit", "quantity")
data %>%
  select(all_of(columns_to_analyze)) %>%
  summarise(across(everything(), list(mean = mean, sd = sd), na.rm = TRUE))

# 4. グループ内でのランキング
data %>%
  group_by(category) %>%
  mutate(
    rank_within_group = row_number(desc(sales)),
    percentile = percent_rank(sales),
    top_10_percent = ntile(sales, 10) >= 9
  ) %>%
  ungroup()

# 5. ウィンドウ関数の活用
data %>%
  arrange(date) %>%
  mutate(
    # 累積統計
    cumulative_sales = cumsum(sales),
    running_avg = cumsum(sales) / row_number(),
    
    # 前後の値との比較
    sales_change = sales - lag(sales),
    sales_change_pct = (sales - lag(sales)) / lag(sales) * 100,
    
    # 前後N期間の統計
    sales_ma = (lag(sales, 2) + lag(sales, 1) + sales + 
                lead(sales, 1) + lead(sales, 2)) / 5
  )

# 6. ネストしたデータとmap関数
nested_analysis <- data %>%
  group_by(region) %>%
  nest() %>%
  mutate(
    # 各グループに対して線形回帰
    model = map(data, ~ lm(sales ~ advertising, data = .)),
    # 予測値の計算
    predictions = map2(model, data, predict),
    # モデルの要約統計
    r_squared = map_dbl(model, ~ summary(.)$r.squared)
  )

⚠️ データ品質管理

🔍 データ品質チェックリスト

# 包括的なデータ品質チェック
quality_check <- function(df) {
  df %>%
    summarise(
      # 基本情報
      n_rows = n(),
      n_cols = ncol(.),
      
      # 欠損値情報
      across(everything(), 
             list(missing_count = ~ sum(is.na(.)),
                  missing_pct = ~ round(sum(is.na(.)) / n() * 100, 2)),
             .names = "{.col}_{.fn}"),
      
      # 重複行の確認
      duplicate_rows = sum(duplicated(.)),
      
      # 数値列の統計サマリー
      across(where(is.numeric),
             list(min = min, max = max, mean = mean, sd = sd),
             na.rm = TRUE,
             .names = "{.col}_{.fn}")
    ) %>%
    pivot_longer(everything()) %>%
    separate(name, into = c("column", "metric"), sep = "_(?=[^_]*$)")
}

💡 実践的アドバイス

📊 データ前処理のプロのコツ

  • 変換前にデータを理解する:分布を可視化してから適切な変換を選択
  • パイプラインを記録する:再現可能な前処理パイプラインを構築
  • 検証用データで変換を確認:テストデータに同じ変換を適用可能か確認
  • ドメイン知識を活用する:業務知識に基づく特徴量エンジニアリング
  • 処理時間を意識する:大容量データでは計算効率も重要

これらの高度なdplyr技法をマスターすることで、複雑な実世界のデータ分析プロジェクトに対応できるようになります。 次の章では、これらの前処理されたデータを美しく効果的に可視化する方法を学びましょう。

📚 学習におすすめの書籍

※ 当サイトはAmazonアソシエイトプログラムに参加しています