Appendix B — Rの基礎

Rには統計処理に便利な関数がbuilt-inで用意されており, これらをbaseRと呼びます. さらに, データ分析に便利な関数を提供するパッケージが多数存在し, 最も有名なものが tidyverse です. この章では, baseRとtidyverseの基礎を学びます.

B.1 baseR

配列

Rでは配列を c() 関数を使って作成します. 例えば, 数値の配列を作成するには次のようにします:

vec <- c(1, 2, 3, 4, 5)
vec
## [1] 1 2 3 4 5

なお, 一定間隔の配列を作成するには seq() または簡略表記の : を使います:

seq_vec <- seq(1, 10, by = 2)
seq_vec
## [1] 1 3 5 7 9
colon_vec <- 1:10
colon_vec
##  [1]  1  2  3  4  5  6  7  8  9 10

for 文

for (i in 1:5) {
  print(i)
}
## [1] 1
## [1] 2
## [1] 3
## [1] 4
## [1] 5

if 文

x <- 3
if (x > 0) {
  print("xは正の数です")
} else if (x < 0) {
  print("xは負の数です")
} else {
  print("xはゼロです")
}
## [1] "xは正の数です"

else ifelse は省略することもできます.

関数

Rでは次のように関数を定義します:

my_function <- function(x) {
  return(x^2)
}
my_function(3)
## [1] 9

データフレーム

df <- data.frame(
  w = seq(1, 2, length.out = 5),
  x = 1:5,
  y = c("a", "b", "c", "d", "e"),
  z = as.Date("2020-01-01") + 0:4
)
df

データフレームは行と列からなる表形式のデータ構造で, 列ごとに異なる型のデータを格納できます. データ分析では, データフレームを使ってデータを整理し, 分析を行います.

Pipe 演算子 |>

パイプ演算子 |> を使うと, 左側のオブジェクトを右側の関数の最初の引数として渡すことができます. つまり, a |> f()f(a) と同じ意味になります. これにより, 関数の入れ子構造を避けて, より読みやすいコードを書くことができます. mean(log(df$w)) をパイプ演算子を使って書くと次のようになります:

df$w |>
  log() |>
  mean()
## [1] 0.3762743

これにより, データフレームの処理がより読みやすくなります.

df |>
  subset(w > 1.5) |> # wが1.5より大きい行を抽出
  transform(log_w = log(w)) # wの対数を新しい列log_wとして追加

B.2 tidyverse によるデータ分析

tidyverse はデータ分析に関する便利なパッケージの集合体で, 主に次のパッケージが含まれています:

  • tibble: データフレームの拡張. あまり意識しなくて良いです.
  • dplyr: データの前処理
  • ggplot2: データの可視化
  • readr: データの読み込み
  • tidyr: データの整形

読み込む際は, library(tidyverse) としても良いですが, 必要なパッケージだけを個別に読み込むことも多いです. ここでは, dplyr, tidyr, ggplot2 を使うので, これらを個別に読み込みます.

library(dplyr)
library(tidyr)
library(ggplot2)

dplyr によるデータの前処理

penguins |>
  select(species, starts_with("bill"), flipper_len_mm = flipper_len) |>
  head()
  • select() はデータフレームから列を選択する関数
  • starts_with() などの便利な関数と組み合わせると強力
  • rename() 関数を使うことなく, 選択する際に名前を変更することもできる.
penguins |>
  filter(species == "Adelie", !is.na(bill_len)) |>
  head()
  • filter() はデータフレームから行を抽出する関数
  • is.na() 関数は欠損値を検出でき, 否定演算子 ! と組み合わせると, 欠損値でない行を抽出できる
penguins |>
  mutate(bill_ratio = bill_len / bill_dep) |>
  head()
  • mutate() はデータフレームに新しい列を追加する関数
  • 既存の列を使って新しい列を作成することができる

データの結合

データの結合には基本的に, dplyr::left_join() を使います. 例えば, nycflights13 パッケージの flights データフレームと airlines データフレームを結合するには次のようにします:

library(nycflights13)

flights |> head()
planes |> head()
flights |>
  left_join(planes, by = c("year", "tailnum")) |>
  select(
    year,
    month,
    day,
    dep_time,
    arr_time,
    carrier,
    flight,
    tailnum
  ) |>
  head()
  • left_join() は左側のデータフレームを基準にして, 右側のデータフレームを結合する関数
  • by 引数で結合のキーとなる列を指定する必要がある
  • 左右のキーの名前が異なる場合は, by = c("left_key" = "right_key") と指定することができる

tidyr によるデータの整形

tb1 <- tibble(
  country = c("Afghanistan", "Brazil", "China"),
  `1999` = c(745, 37737, 212258),
  `2000` = c(2666, 80488, 213766)
)

tb1
tb1 |>
  pivot_longer(cols = c(`1999`, `2000`), names_to = "year", values_to = "cases")
  • pivot_longer() はデータフレームを長い形式に変換する関数
  • cols 引数で変換する列を指定する必要がある
  • names_to 引数で新しい列の名前を指定できる
  • values_to 引数で新しい列の値の名前を指定できる
tb2 <- tibble(
  country = c(rep("Afghanistan", 4), rep("Brazil", 2)),
  year = c(rep(c(1999, 2000), each = 2), 1999, 1999),
  type = rep(c("cases", "population"), 3),
  count = c(745, 19987071, 2666, 20595360, 37737, 172006362)
)
tb2
tb2 |>
  pivot_wider(names_from = type, values_from = count)
  • pivot_wider() はデータフレームを広い形式に変換する関数
  • names_from 引数で新しい列の名前を指定する必要がある
  • values_from 引数で新しい列の値の名前を指定できる

ggplot2 によるデータの可視化

ggplot2 は Grammar of Graphics (Wilkinson 1999) に基づいて設計されたデータ可視化のためのパッケージです.

NoteGrammar of Graphics (Wilkinson 1999)
  1. グラフィックスは文法的な要素の異なる層から構成されている
  2. プロットは適切な美的マッピングを使用して構築され、これらのプロットを意味のあるものにする

これだけだと分かりにくいと思いますが, 次に示す例を見れば, 層を重ねていく様子が分かると思います.

penguins |>
  ggplot(aes(x = flipper_len, y = bill_len)) +
  geom_point()

  • ggplot() 関数はグラフの基本的な構造を定義する関数
  • aes() 関数は美的マッピングを定義する関数 (x軸とy軸にどの変数を割り当てるかなど)
  • geom_point() 関数は散布図を描く関数 (点をプロットするレイヤー)
penguins |>
  ggplot(aes(x = flipper_len, y = bill_len)) +
  geom_point() +
  facet_wrap(~species)

  • facet_wrap() 関数はグラフをファセット (小さなグラフ) に分割する関数
penguins |>
  ggplot(aes(x = flipper_len, y = bill_len)) +
  geom_point() +
  facet_wrap(~species) +
  geom_smooth(method = "lm", formula = y ~ x, se = FALSE)

  • geom_smooth() 関数はデータにフィットする曲線を描く関数
  • method = "lm" は線形モデルを使用してフィットすることを指定する引数
  • formula = y ~ x はフィットするモデルの式を指定する引数
  • se = FALSE は信頼区間の表示を無効にする引数
penguins |>
  ggplot(aes(x = flipper_len, y = bill_len)) +
  geom_point() +
  facet_wrap(~species) +
  geom_smooth(method = "lm", formula = y ~ x, se = FALSE) +
  theme(axis.text.x = element_text(color = "red"))

このように, ggplot2 ではグラフを構築する際にレイヤーを重ねていくことで, 複雑なグラフを作成することができます.label

penguins |>
  ggplot(aes(x = flipper_len, y = bill_len, color = species, shape = species)) +
  geom_point() +
  geom_smooth(method = "lm", formula = y ~ x, se = FALSE)

  • color 美的マッピングを追加することで, 種類ごとに色分けされたグラフを作成することができます.
  • shape 美的マッピングを追加することで, 種類ごとに形を変えることができます.
  • どちらか一方を指定するだけでもいいですが, 両方を指定することをお勧めします. (色覚障害の方も見やすくなるため, 白黒印刷しても見やすくなるため)