第5章 データの結合

観察データを分析する際、大抵の場合は複数のデータを集めて、結合した上で分析をする必要があります。

結合の方法には

  1. 行方向の結合:同じ変数を持っているデータ同士を結合させて観察数を増やす。
  2. 列方向の結合:同じ種類の観察を持っているデータ同士を結合して変数の数を増やす。

の2種類があります。

library(tidyverse)

5.1 行方向の結合

行方向にデータを結合する必要がある場面としてよくあるのはデータが年や地域ごとに分割されているときです。 例えば、(なぜか)一人あたりGDPのデータが日本中国で別々のデータになっているとします。

japan <- read_csv("data/wb_gdp_pc_jp.csv")
## Parsed with column specification:
## cols(
##   name = col_character(),
##   year = col_double(),
##   gdp_pc = col_double()
## )
japan
china <- read_csv("data/wb_gdp_pc_cn.csv")
## Parsed with column specification:
## cols(
##   name = col_character(),
##   year = col_double(),
##   gdp_pc = col_double()
## )
china

これを結合するにはrbind()(row方向の結合)を使いますが、それぞれ同じ変数名を持っている必要があります。

data <- rbind(japan, china)
unique(data$name)
## [1] "Japan" "China"

無事、日本と中国が一つのデータに含まれています。

tidyverseで行方向の結合の場合、bind_rows()という関数を使います。

data <- bind_rows(japan, china)
unique(data$name)
## [1] "Japan" "China"

5.2 列方向の結合

変数を増やすためにデータセットを都合するには列方向に結合する必要があります。 例えば、一人あたりGDPのデータGDP成長率のデータを結合するとします。

gdp_pc <- read_csv("data/wb_gdp_pc.csv", skip = 4) %>% 
  select(-"Country Code", -"Indicator Name", -"Indicator Code", -X64)%>% 
  rename(name = "Country Name") %>% 
  gather(key = year, value = gdp_pc, -name) %>% 
  mutate(year = as.numeric(year))
## Warning: Missing column names filled in: 'X64' [64]
## Parsed with column specification:
## cols(
##   .default = col_double(),
##   `Country Name` = col_character(),
##   `Country Code` = col_character(),
##   `Indicator Name` = col_character(),
##   `Indicator Code` = col_character(),
##   `2018` = col_logical(),
##   X64 = col_logical()
## )
## See spec(...) for full column specifications.
head(gdp_pc)
gdp_gr <- read_csv("data/wb_gdp_growth.csv", skip = 4) %>% 
  select(-"Country Code", -"Indicator Name", -"Indicator Code", -X64)%>% 
  rename(name = "Country Name") %>% 
  gather(key = year, value = gdp_gr, -name) %>% 
  mutate(year = as.numeric(year))
## Warning: Missing column names filled in: 'X64' [64]
## Parsed with column specification:
## cols(
##   .default = col_double(),
##   `Country Name` = col_character(),
##   `Country Code` = col_character(),
##   `Indicator Name` = col_character(),
##   `Indicator Code` = col_character(),
##   `1960` = col_logical(),
##   `2018` = col_logical(),
##   X64 = col_logical()
## )
## See spec(...) for full column specifications.
head(gdp_gr)
  • [ロング・ワイド変換]で紹介するようにワイド形式からロング形式に変換しています。

つまり、モチベーションとしてはこの2つのデータセットを結合して、各国の各年の一人あたりGDPとGDP成長率のデータセットを作成したいとします。

merge()を使うことでそれが可能になりますが、byによって結合するデータに共通するそれぞれの観察を特定する変数を指定します。 この場合、各観察は各国の各年なので、nameyearを指定します。

data <- merge(gdp_pc, gdp_gr, by = c("name", "year"))
head(data)

tidyverseで列方向の結合の場合、以下の4つの関数のうちの一つを選びます。 ここでは、xyというデータセットを結合するとします。

  1. left_join(x, y)xにマッチする観察のみを残す。
  2. right_join(x, y)yにマッチする観察のみを残す。
  3. inner_join(x, y):両者に共通する観察のみを残す。
  4. full_join(x, y):どちらかに含まれる観察を全て残す。

例えば、次のようなXYというデータセットがあり、同じidのサンプル同士で結合するとします。

X <- tibble(id = c(1,2,3), x = c("x1", "x2", "x3"))
Y <- tibble(id = c(1,2,4), y = c("y1", "y2", "y4"))
X
Y

left_join()の場合はXにあるデータだけ残ります。

left_join(X, Y, by = "id")

right_join()の場合ははYにあるデータだけ残ります。

right_join(X, Y, by = "id")

inner_join()の場合は共通して存在するサンプルに、full_join()の場合は少なくともどちらかに存在するサンプルになるので、後者が一番保守的な結合になります。

inner_join(X, Y, by = "id")
full_join(X, Y, by = "id") 
  • なお、byで指定しなくても自動で結合してくれますが、一般的にはbyで指定したほうがいいでしょう。

5.2.1 観察の選択**

semi_join()anti_join()という関数ではデータの結合ではなく、マッチングに応じた観察の選択が可能です。

  1. semi_join(x, y)yとマッチしたxだけを返す。
  2. anti_join(x, y)yとマッチしなかったxだけを返す。
semi_join(X, Y, by = "id")
anti_join(X, Y, by = "id")

5.2.2 データフレームの作成

tidyverseにおけるデータフレームを作成する関数はtibble()です。

tibble(name = c("日本", "アメリカ", "中国"),
       code = c("JPN", "USA", "CHN"))

やはりデータフレームはベクトルからも作れます。

name <- c("日本", "アメリカ", "中国")
code <- c("JPN", "USA", "CHN")
tibble(name, code)