この記事ではtidyverseパッケージを使ったデータ結合を解説します。base Rの`merge()`関数を使った基本的な方法については[[R - データ結合の基本(merge)]]を参照してください。
データ分析において、複数のテーブルを結合する操作は非常に重要です。SQLのJOIN操作と同様の処理を、Rのtidyverseパッケージでどのように実現できるかを、患者データと体重データを例にして解説します。
tidyverseの利点は、パイプ演算子(`%>%`)を使って処理を連鎖的に記述できる点と、関数名が直感的で読みやすい点です。
## 完全なコード
```r
# 必要なライブラリの読み込み
library(tidyr)
library(dplyr)
# サンプルデータ1: 患者の基本情報
patients <- data.frame(
  id = c(1001, 1002, 1003, 1004, 1005),
  name = c("山田太郎", "田中花子", "佐藤次郎", "鈴木美咲", "高橋健太"),
  age = c(45, 32, 67, 28, 51)
)
# サンプルデータ2: 体重データ
weights <- data.frame(
  id = c(1001, 1002, 1003, 1005, 1006),
  weight_kg = c(70, 52, 82, 55, 75)
)
# INNER JOIN - 両方のデータが存在する患者のみ
inner_result <- patients %>%
  inner_join(weights, by = "id")
print("INNER JOIN結果:")
print(inner_result)
# LEFT JOIN - 全ての患者情報を保持(体重データがない場合はNA)
left_result <- patients %>%
  left_join(weights, by = "id")
print("LEFT JOIN結果:")
print(left_result)
# RIGHT JOIN - 全ての体重データを保持(患者情報がない場合はNA)
right_result <- patients %>%
  right_join(weights, by = "id")
print("RIGHT JOIN結果:")
print(right_result)
# FULL JOIN - 両方のデータを全て保持
full_result <- patients %>%
  full_join(weights, by = "id")
print("FULL JOIN結果:")
print(full_result)
```
## ステップバイステップ解説
### 1. ライブラリの読み込み
```r
library(tidyr)
library(dplyr)
```
tidyrとdplyrパッケージを読み込みます。JOIN操作はdplyrの機能ですが、データ処理全般でtidyrも使用することが多いため、両方を読み込んでいます。
### 2. サンプルデータの作成
まず患者の基本情報を作成します:
```r
patients <- data.frame(
  id = c(1001, 1002, 1003, 1004, 1005),
  name = c("山田太郎", "田中花子", "佐藤次郎", "鈴木美咲", "高橋健太"),
  age = c(45, 32, 67, 28, 51)
)
```
```
> print(patients)
    id     name age
1 1001   山田太郎  45
2 1002   田中花子  32
3 1003   佐藤次郎  67
4 1004   鈴木美咲  28
5 1005   高橋健太  51
```
次に体重データを作成します:
```r
weights <- data.frame(
  id = c(1001, 1002, 1003, 1005, 1006),
  weight_kg = c(70, 52, 82, 55, 75)
)
```
```
> print(weights)
    id weight_kg
1 1001        70
2 1002        52
3 1003        82
4 1005        55
5 1006        75
```
注目すべき点は、患者データにはid 1004が含まれていますが体重データにはなく、逆に体重データにはid 1006が含まれていますが患者データにはないということです。この違いによって、各JOIN操作の結果がどのように変わるかを確認できます。
### 3. INNER JOIN(内部結合)
```r
inner_result <- patients %>%
  inner_join(weights, by = "id")
```
```
> print(inner_result)
    id     name age weight_kg
1 1001   山田太郎  45        70
2 1002   田中花子  32        52
3 1003   佐藤次郎  67        82
4 1005   高橋健太  51        55
```
INNER JOINは両方のテーブルに存在するレコードのみを返します。id 1004(鈴木美咲)は体重データがないため除外され、id 1006は患者データがないため除外されています。
### 4. LEFT JOIN(左外部結合)
```r
left_result <- patients %>%
  left_join(weights, by = "id")
```
```
> print(left_result)
    id     name age weight_kg
1 1001   山田太郎  45        70
2 1002   田中花子  32        52
3 1003   佐藤次郎  67        82
4 1004   鈴木美咲  28        NA
5 1005   高橋健太  51        55
```
LEFT JOINは左のテーブル(patients)のすべてのレコードを保持します。id 1004(鈴木美咲)の体重データがないため、weight_kgにはNAが入ります。
### 5. RIGHT JOIN(右外部結合)
```r
right_result <- patients %>%
  right_join(weights, by = "id")
```
```
> print(right_result)
    id     name age weight_kg
1 1001   山田太郎  45        70
2 1002   田中花子  32        52
3 1003   佐藤次郎  67        82
4 1005   高橋健太  51        55
5 1006     <NA>  NA        75
```
RIGHT JOINは右のテーブル(weights)のすべてのレコードを保持します。id 1006は患者データがないため、nameとageにはNAが入ります。
### 6. FULL JOIN(完全外部結合)
```r
full_result <- patients %>%
  full_join(weights, by = "id")
```
```
> print(full_result)
    id     name age weight_kg
1 1001   山田太郎  45        70
2 1002   田中花子  32        52
3 1003   佐藤次郎  67        82
4 1004   鈴木美咲  28        NA
5 1005   高橋健太  51        55
6 1006     <NA>  NA        75
```
FULL JOINは両方のテーブルのすべてのレコードを保持します。id 1004とid 1006の両方が含まれ、欠損している部分にはNAが入ります。
## まとめ
RのtidyverseパッケージでのJOIN操作は、SQLの対応する操作と非常に似ており、直感的に理解できます。データ分析の現場では、データの欠損パターンや分析の目的に応じて適切なJOIN方法を選択することが重要です。
- **INNER JOIN**: 完全なデータペアのみが必要な場合
- **LEFT JOIN**: 主テーブルのすべてのレコードを保持したい場合
- **RIGHT JOIN**: 副テーブルのすべてのレコードを保持したい場合
- **FULL JOIN**: 両方のテーブルのすべての情報を保持したい場合
実際の医療データ分析では、患者の基本情報と検査結果、投薬記録などを結合する際に、これらの操作を頻繁に使用します。
パイプ演算子を使わないシンプルな方法や、base Rの`merge()`関数との比較については[[R - データ結合の基本(merge)]]を参照してください。