🔄
CHAPTER 04

データ再構造化の魔術

tidyrでデータを自在に操る。Wide/Long形式の変換、欠損値の優雅な処理、複雑なデータ構造の整理術をマスターし、データサイエンスの真の力を解き放とう。

tidyrとは?

tidyrは「tidy data」の原則に基づいて設計された、データ再構造化の専門パッケージです。混沌としたデータを美しく整理し、分析しやすい形に変換する強力なツールを提供します。

現実のデータは常に理想的な形ではありません。Excel形式の幅の広いテーブル、不規則な欠損値、ネストされた複雑な構造...。tidyrは、これらすべてを「tidy」な形に変換する魔法を提供します。

tidyr_setup.R
# tidyrの読み込み(tidyverseに含まれる) library(tidyr) library(dplyr) # Tidy Dataの3つの原則 # 1. 各変数は1つの列 # 2. 各観測値は1つの行 # 3. 各値は1つのセル

データ形状の変換

データの形状変換は、tidyrの最も重要な機能です。Wide形式(横に広い)とLong形式(縦に長い)を自在に変換し、分析の目的に最適な形にデータを整形できます。

pivot_longer()

Wide形式からLong形式への変換。複数の列を1つの列にまとめ、データを「長く」します。

pivot_longer(cols, names_to, values_to)

pivot_wider()

Long形式からWide形式への変換。1つの列の値を複数の列に展開し、データを「広く」します。

pivot_wider(names_from, values_from)

📊 pivot_longer(): Wide → Long変換

売上データをExcel形式(Wide)から分析用形式(Long)に変換する実例を見てみましょう。

pivot_longer_example.R
# Wide形式の売上データ(Excel形式) sales_wide <- data.frame( 店舗 = c("東京店", "大阪店", "名古屋店"), Q1 = c(1200, 980, 750), Q2 = c(1350, 1100, 820), Q3 = c(1180, 1250, 890), Q4 = c(1420, 1380, 950) ) # Long形式に変換(分析しやすい形に) sales_long <- sales_wide %>% pivot_longer( cols = starts_with("Q"), # Q1,Q2,Q3,Q4の列を対象 names_to = "四半期", # 列名が入る新しい列 values_to = "売上" # 値が入る新しい列 ) print(sales_long)

🔄 データ変換結果

Wide形式(変換前)
店舗 Q1 Q2 Q3 Q4
東京店 1200 1350 1180 1420
大阪店 980 1100 1250 1380
名古屋店 750 820 890 950
Long形式(変換後)
店舗 四半期 売上
東京店 Q1 1200
東京店 Q2 1350
東京店 Q3 1180
東京店 Q4 1420
大阪店 Q1 980
... ... ...

📈 pivot_wider(): Long → Wide変換

アンケートデータをクロス集計表形式に変換する例を見てみましょう。

pivot_wider_example.R
# Long形式のアンケートデータ survey_long <- data.frame( 回答者ID = rep(1:4, each = 3), 質問項目 = rep(c("満足度", "利便性", "価格"), 4), 評価 = c(5, 4, 3, 4, 5, 4, 3, 3, 5, 5, 4, 4) ) # Wide形式に変換(クロス集計表形式) survey_wide <- survey_long %>% pivot_wider( names_from = 質問項目, # この列の値が新しい列名になる values_from = 評価 # この列の値が各セルに入る ) print(survey_wide)

🔄 データ変換結果

Long形式(変換前)
回答者ID 質問項目 評価
1 満足度 5
1 利便性 4
1 価格 3
2 満足度 4
... ... ...
Wide形式(変換後)
回答者ID 満足度 利便性 価格
1 5 4 3
2 4 5 4
3 3 3 5
4 5 4 4

欠損値の優雅な処理

現実のデータには欠損値が付き物です。tidyrは、欠損値を適切に処理し、データの完全性を保ちながら分析を進めるための強力なツールを提供します。

drop_na()

欠損値を含む行を削除します。シンプルで直接的なアプローチです。

drop_na(columns)

fill()

前後の値で欠損値を埋めます。時系列データに特に有効です。

fill(columns, .direction)

replace_na()

欠損値を指定した値で置換します。カスタマイズされた補完が可能です。

replace_na(list(col = value))

complete()

データの組み合わせを完全にし、暗黙的な欠損値を明示的にします。

complete(columns, fill)

🔍 欠損値処理の実践

センサーデータの欠損値を様々な方法で処理する例を見てみましょう。

missing_data_handling.R
# 欠損値を含むセンサーデータ sensor_data <- data.frame( timestamp = seq(as.POSIXct("2023-01-01 00:00:00"), by = "hour", length.out = 10), temperature = c(22.5, NA, 23.1, 22.8, NA, 24.2, 24.5, NA, 23.9, 23.7), humidity = c(65, 68, NA, 70, 72, NA, 69, 67, 65, NA) ) # 方法1: 欠損値のある行を削除 clean_data <- sensor_data %>% drop_na() # 方法2: 前の値で埋める(温度センサー) filled_data <- sensor_data %>% fill(temperature, .direction = "down") %>% fill(humidity, .direction = "up") # 方法3: 平均値で置換 imputed_data <- sensor_data %>% replace_na(list( temperature = mean(sensor_data$temperature, na.rm = TRUE), humidity = mean(sensor_data$humidity, na.rm = TRUE) )) print("補完後のデータ:") print(imputed_data)

🔄 欠損値処理結果

元データ(欠損値あり)
時刻 温度 湿度
00:00 22.5 65
01:00 NA 68
02:00 23.1 NA
03:00 22.8 70
04:00 NA 72
補完後データ
時刻 温度 湿度
00:00 22.5 65
01:00 23.3 68
02:00 23.1 68.0
03:00 22.8 70
04:00 23.3 72

🎯 高度なデータ整理術

separate()とunite()を使って、複雑な文字列データを分割・結合する方法を学びましょう。

advanced_tidyr.R
# 複雑な文字列データ user_data <- data.frame( user_info = c("田中太郎_25_東京", "佐藤花子_30_大阪", "山田次郎_28_名古屋"), score = c(85, 92, 78) ) # 1つの列を複数の列に分割 separated_data <- user_data %>% separate( col = user_info, into = c("名前", "年齢", "都市"), sep = "_" ) %>% mutate(年齢 = as.numeric(年齢)) # 複数の列を1つに結合 united_data <- separated_data %>% unite( col = "ID", 名前, 都市, sep = "@", remove = FALSE # 元の列を残す ) print(united_data)