tidyverse パッケージは、readr パッケージ、dplyr パッケージ、ggplot2 パッケージ、tidyr パッケージなどのデータの操作および視覚化用のパッケージをまとめたパッケージである。tidyverse を利用ことで、データの操作や視覚化が容易になるだけでなく、コーディング量が減り、コーディングミスによる間違いなども起こしにくく、解析作業が効率的になる。

tidyverse

tidyverse インストール

tidyverse パッケージは CRAN のパッケージとして提供されている。CRAN のパッケージをインストールするとき、install.packages 関数する。tidyverse パッケージをインストールすることで、readr パッケージ、dplyr パッケージ、ggplot2 パッケージ、tidyr パッケージなどを自動的にインストールされる。

install.packages('tidyverse')

tidyverse の呼び出し

tidyverse パッケージを呼び出すときは、R の他のパッケージと同様に library 関数を使う。tidyverse パッケージを呼び出すだけで、自動的に dplyr や ggplot2 などのパッケージも呼び出され、使えるようになる。

library(tidyverse)
## ── Attaching packages ────────────────────────────────────────────────────────────────────────────────────── tidyverse 1.2.1 ──
## ✔ ggplot2 3.2.1     ✔ purrr   0.3.2
## ✔ tibble  2.1.3     ✔ dplyr   0.8.3
## ✔ tidyr   0.8.3     ✔ stringr 1.4.0
## ✔ readr   1.3.1     ✔ forcats 0.4.0
## ── Conflicts ───────────────────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()

readr

readr パッケージは、ファイルからデータを読み込んだり、データをファイルに書き出したり、文字列をパースしたりする際に利用する関数をまとめたパッケージである。これらの関数は R に標準実装されているが、readr の関数を使用した方が、R の標準関数に比べて速度が速く、効率的な処理を行える。

ファイルの読み込み

readr パッケージでは、ファイルからデータを読み込むときに使用する関数として read_csvread_tsv などが用意されている。これらの関数は R の標準関数である read.csvread.table 関数とほぼ同じ機能を持つが、次のような点で異なっている。

  • readr パッケージの関数が R 標準関数に比べ、ファイルの読み込み速度が約 10 倍速い。
  • read_csvread_tsv 関数にはお節介な機能がない。
    • 文字列データを勝手に因子型に変換しない。
    • 列名を勝手に(X.1、X.2、X.3 などのように)変換しない。
  • 読み込まれたデータは tibble 型のオブジェクとして保存される。(R 標準関数ではデータフレーム型のオブジェクトとして保存される。)

CSV ファイルの読み込みは read_csv 関数を使用する。

d <- read_csv('data/rice.csv')
head(d)

TSV ファイルの読み込みは read_tsv 関数を使用する。

d <- read_tsv('data/rice.txt')
head(d)

区切り文字を指定して、ファイルからデータを読み込むときに read_delim 関数を使用する。このとき、区切り文字を delim オプションで指定する。

d <- read_delim('data/rice.txt', delim = '\t')
head(d)

ファイル書き出し

ファイル書き出し用の関数には write_csvwrite_tsvwrite_delim などの関数が用意されている。これら関数を使用して、データをファイルに保存する際に、文字コードが UTF-8 として保存される。使い方は R の標準関数とほぼ同じように使う。

write_csv(d, 'data/results.csv')
write_tsv(d, 'data/results.csv')
write_tsv(d, 'data/results.csv', delim = ';')

文字列パース

readr パッケージには文字列をパースするための関数が用意されている。

関数 機能
parse_logical 文字列を理論型(TRUE または FALSE)に変換する。
parse_integer 文字列を整数型に変換する。
parse_double 文字列を小数型に変換する。
parse_character 文字列を文字型に変換する。UTF-8 以外の文字列コードから UTF-8 に変換するときに使用する。
parse_datetime 文字列を datetime 型に変換する。
parse_date 文字列を date 型に変換する。
parse_time 文字列を time 型に変換する。
parse_number 文字列中に含まれている数字を整数に変換する。
x <- c('TRUE', 'FALSE')
y <- parse_logical(x)
print(y)
## [1]  TRUE FALSE
x <- c('64')
y <- parse_integer(x)
print(y)
## [1] 64
x <- c('3.14')
y <- parse_integer(x)
## Warning: 1 parsing failure.
## row col               expected actual
##   1  -- no trailing characters    .14
print(y)
## [1] NA
## attr(,"problems")
## # A tibble: 1 x 4
##     row   col expected               actual
##   <int> <int> <chr>                  <chr> 
## 1     1    NA no trailing characters .14
x <- c('3.14')
y <- parse_double(x)
print(y)
## [1] 3.14
x <- "\x82\xb1\x82\xf1\x82\xc9\x82\xbf\x82\xcd"
y <- parse_character(x, locale = locale(encoding = "Shift-JIS"))
print(y)
## [1] "こんにちは"
x <- "2019-10-20 10:00:00"
y <- parse_datetime(x)
print(y)
## [1] "2019-10-20 10:00:00 UTC"
x <- "2019-10-20"
y <- parse_date(x)
print(y)
## [1] "2019-10-20"
x <- "23:00:00"
y <- parse_time(x)
print(y)
## 23:00:00
x <- "11:00:00 pm"
y <- parse_time(x)
print(y)
## 23:00:00
print(parse_number("123,456,789"))  # US, JP, ...
## [1] 123456789
print(parse_number("123.456.789", locale = locale(grouping_mark = "."))) # EU
## [1] 123456789
print(parse_number("123'456'789", locale = locale(grouping_mark = "'"))) # CH
## [1] 123456789

dplyr

dplyr は表型データの操作に特化した R のパッケージである。dplyr パッケージには、表型データの中からサブセットを抽出したりする関数や抽出したサブセットに対して集計を行う関数などが多数用意されている。dplyr で扱うデータは数百 MB から 2 GB 前後のサイズを想定している。このサイズを超えるような 10〜100 GB 規模なビッグデータなどを取り扱う場合は、 data.table パッケージを使用した方が無難。

dplyr の関数の記述方法が非常にシンプルであり、可読性が良い。dplyr を使用することで、研究者はデータの操作や集計に集中することができ、集計等に関係しない無駄なコードを書かなくて済む。

dplyr パッケージを使わないデータ操作例

R では、データフレームの中からある条件を満たすサブセットを抽出し、そのサブセットの平均値を求めたりすることが簡単にできる。ここで、 rice.txt データセットを使って、データの操作方法を示す。rice データセットは 7 列を持ち、それぞれの列が個体番号(replicate)、ブロック番号(block)、根部乾燥重量(root_dry_mass)、地上部乾燥重量(shoot_dry_mass)、系統処理(trt)、処理(fert)、系統(variety)からなる。

d <- read.table('data/rice.txt', header = TRUE, sep = '\t')
head(d)
##   replicate block root_dry_mass shoot_dry_mass trt fert variety
## 1         1     1            56            132 F10  F10      wt
## 2         2     1            66            120 F10  F10      wt
## 3         3     1            40            108 F10  F10      wt
## 4         4     1            43            134 F10  F10      wt
## 5         5     1            55            119 F10  F10      wt
## 6         6     1            66            125 F10  F10      wt

ここで、例えば、各系統(wt 系統および ANU843 系統)に対して、根部乾燥重量を求める場合は、データフレームに対して、次のようの操作を行うことで計算できる。

wt <- d$root_dry_mass[d$variety == 'wt']
ANU843 <- d$root_dry_mass[d$variety == 'ANU843']

print(mean(wt))
## [1] 26.47222
print(mean(ANU843))
## [1] 9.666667

平均値・最大値・最小値などの簡単な値を求めるとき、R の標準関数の一つである aggregate 関数を使うと便利である。

aggregate(d$root_dry_mass, by = list(variety = d$variety), mean)
##   variety         x
## 1  ANU843  9.666667
## 2      wt 26.472222

wt 系統および ANU843 系統の中に、F10 処理、NH4Cl 処理、NH4NO3 処理の 3 つの処理群が含まれている。ここで、wt 系統と ANU843 系統の各処理群それぞれに対して、根部乾燥重量の平均を計算してみる。

wt.F10 <- d$root_dry_mass[d$variety == 'wt' & d$fert == 'F10']
wt.NH4Cl <- d$root_dry_mass[d$variety == 'wt' & d$fert == 'NH4Cl']
wt.NH4NO3 <- d$root_dry_mass[d$variety == 'wt' & d$fert == 'NH4NO3']
ANU843.F10 <- d$root_dry_mass[d$variety == 'ANU843' & d$fert == 'F10']
ANU843.NH4Cl <- d$root_dry_mass[d$variety == 'ANU843' & d$fert == 'NH4Cl']
ANU843.NH4NO3 <- d$root_dry_mass[d$variety == 'ANU843' & d$fert == 'NH4NO3']

m <- c(mean(wt.F10), mean(wt.NH4Cl), mean(wt.NH4NO3),
            mean(ANU843.F10), mean(ANU843.NH4Cl), mean(ANU843.NH4NO3))
print(m)
## [1] 49.500000 12.583333 17.333333  6.000000  9.166667 13.833333

複数条件の組み合わせでも aggregate 関数が使える。例えば次のように by オプションに、2 つの条件を与えればよい。

aggregate(d$root_dry_mass, by = list(variety = d$variety, fert = d$fert), mean)
##   variety   fert         x
## 1  ANU843    F10  6.000000
## 2      wt    F10 49.500000
## 3  ANU843  NH4Cl  9.166667
## 4      wt  NH4Cl 12.583333
## 5  ANU843 NH4NO3 13.833333
## 6      wt NH4NO3 17.333333

dplyr の基本的な使い方

dplyr を使用してデータ操作を扱うとき、データの流れに着目するとわかりやすい。例えば、d というデータに対して A 処理を行なった後に、B 処理を行い、その結果を x に保存したい場合は、dABx という流れに着目すると、dplyr のルールに従うと次のように記述することができる。d の内容を関数 A に流すときに %>% 演算子を使用する。次に、A 関数で処理した結果を B 関数に流すときに同様に %>% 演算子を使用する。最後に、関数 B の処理結果を x に代入したいから、R の基本文法により <- を使用する。

x <- d %>% A %>% B

dplyr の記述ルールを踏まえて、wt 系統の個体数を求めるには、次のように行う。データ dgroup_by 関数に流し、ここで variety ごとにグループ分けを行う。グループ分けを行なった後に、各グループをさらに次の summarise 関数に流し、平均を求める処理を行なっている。

d <- read_tsv('data/rice.txt')
## Parsed with column specification:
## cols(
##   replicate = col_double(),
##   block = col_double(),
##   root_dry_mass = col_double(),
##   shoot_dry_mass = col_double(),
##   trt = col_character(),
##   fert = col_character(),
##   variety = col_character()
## )
head(d)
## # A tibble: 6 x 7
##   replicate block root_dry_mass shoot_dry_mass trt   fert  variety
##       <dbl> <dbl>         <dbl>          <dbl> <chr> <chr> <chr>  
## 1         1     1            56            132 F10   F10   wt     
## 2         2     1            66            120 F10   F10   wt     
## 3         3     1            40            108 F10   F10   wt     
## 4         4     1            43            134 F10   F10   wt     
## 5         5     1            55            119 F10   F10   wt     
## 6         6     1            66            125 F10   F10   wt
variety_ave <- d %>% 
                group_by(variety) %>%
                summarise(mass_ave = mean(root_dry_mass))
head(variety_ave)
## # A tibble: 2 x 2
##   variety mass_ave
##   <chr>      <dbl>
## 1 ANU843      9.67
## 2 wt         26.5

各系統の各処理群に対して平均を求める場合は、aggregate 関数と同様に、group_by のところに条件を 2 つ書けばよい。

variety_ave <- d %>% 
                group_by(variety, fert) %>%
                summarise(mass_ave = mean(root_dry_mass))
head(variety_ave)
## # A tibble: 6 x 3
## # Groups:   variety [2]
##   variety fert   mass_ave
##   <chr>   <chr>     <dbl>
## 1 ANU843  F10        6   
## 2 ANU843  NH4Cl      9.17
## 3 ANU843  NH4NO3    13.8 
## 4 wt      F10       49.5 
## 5 wt      NH4Cl     12.6 
## 6 wt      NH4NO3    17.3

このように、dplyr ではデータの流れに着目して、データの操作や集計を行なっていくことができる。研究者がデータ操作・データ集計に関係のないコードを書く必要がなく、効率的である。

dplyr の基本関数

dplyr パッケージの中で、表データ操作の目的でよく使われる関数として、次のような関数がある。

関数 動作
select 与えられた条件に基づいて、特定の列を抽出する。
filter 与えられた条件に基づいて、特定の行を抽出する。
arrange 与えられた条件に基づいて、行を並べ替える。
group_by 与えられた条件に基づいて、データセット全体をいくつかのグループに分ける。
summarise 最大値・最小値・平均値を求めるなどのデータの集計を行う。
mutate 既存のデータセットに新しい列を加える。

また、 2 つの表データを結合したりする関数も用意されている。

関数 動作
inner_join 2 つの表データを内部結合させる。
left_join 2 つの表データを左外部結合させる。
right_join 2 つの表データを右外部結合させる。
full_join 2 つの表データを完全外部結合させる。

dplyr::select 関数

select 関数は、与えられた条件に基づいて、特定の列を抽出する関数である。例えば rice データセットから、系統(variety)、処理(fert)、根部乾燥重量(root_dry_mass)、地上部乾燥重量(shoot_dry_mass)の 4 列だけを取り出してサブセットを作成したい場合は、次のようにする。

# d.subset <- d[, c('variety', 'fert', 'root_dry_mass', 'shoot_dry_mass')]
d.subset <- d %>% select(variety, fert, root_dry_mass, shoot_dry_mass)
head(d.subset)
## # A tibble: 6 x 4
##   variety fert  root_dry_mass shoot_dry_mass
##   <chr>   <chr>         <dbl>          <dbl>
## 1 wt      F10              56            132
## 2 wt      F10              66            120
## 3 wt      F10              40            108
## 4 wt      F10              43            134
## 5 wt      F10              55            119
## 6 wt      F10              66            125

select 関数に列名を指定するとき、- をつけると、その列を含まないようなサブセットが作成される。

# d.subset <- d[, -c('replicate', 'block', 'trt')]
d.subset <- d %>% select(-replicate, -block, -trt)
head(d.subset)
## # A tibble: 6 x 4
##   root_dry_mass shoot_dry_mass fert  variety
##           <dbl>          <dbl> <chr> <chr>  
## 1            56            132 F10   wt     
## 2            66            120 F10   wt     
## 3            40            108 F10   wt     
## 4            43            134 F10   wt     
## 5            55            119 F10   wt     
## 6            66            125 F10   wt

select 関数に列名ではなく、条件を与えて列名を列を抽出することもできる。例えば、列名に mass を含む列を抽出する場合は次のようにする。

d.subset <- d %>% select(contains('mass'))
head(d.subset)
## # A tibble: 6 x 2
##   root_dry_mass shoot_dry_mass
##           <dbl>          <dbl>
## 1            56            132
## 2            66            120
## 3            40            108
## 4            43            134
## 5            55            119
## 6            66            125

抽出条件を与えるときに使用した contains 関数の他に、starts_withends_withmatches などの関数も使用できる。

dplyr::filter 関数

filter 関数は与えられた条件に基づいて、特定の行を抽出する関数である。例えば、根部乾燥重量が 50 以上の行を抽出するには、次のように行う。

d.subset <- d %>% filter(root_dry_mass > 50)
head(d.subset)
## # A tibble: 5 x 7
##   replicate block root_dry_mass shoot_dry_mass trt   fert  variety
##       <dbl> <dbl>         <dbl>          <dbl> <chr> <chr> <chr>  
## 1         1     1            56            132 F10   F10   wt     
## 2         2     1            66            120 F10   F10   wt     
## 3         5     1            55            119 F10   F10   wt     
## 4         6     1            66            125 F10   F10   wt     
## 5         8     2            67            122 F10   F10   wt

条件が複数ある場合は、それらの条件を順に filter 関数に加えればよい。例えば、wt 系統かつ根部乾燥重量が 50 以上の行を抽出するには、次のようにする。

d.subset <- d %>% filter(root_dry_mass >= 50, variety == 'wt')
head(d.subset)
## # A tibble: 5 x 7
##   replicate block root_dry_mass shoot_dry_mass trt   fert  variety
##       <dbl> <dbl>         <dbl>          <dbl> <chr> <chr> <chr>  
## 1         1     1            56            132 F10   F10   wt     
## 2         2     1            66            120 F10   F10   wt     
## 3         5     1            55            119 F10   F10   wt     
## 4         6     1            66            125 F10   F10   wt     
## 5         8     2            67            122 F10   F10   wt

複数条件の場合は & および | を使って AND 演算および OR 演算を行うことができる。例えば、「wt 系統」、「根部乾燥重量が 50 以上」、「地上部乾燥重量が 120 以上」の 3 つの条件を同時に満たす行を抽出する場合は、次のようにする。 ただし、複数の条件をカンマで区切って与える場合は AND 演算の結果が行われる。

d.subset <- d %>% filter(variety == 'wt', root_dry_mass >= 50, shoot_dry_mass >= 120)
# d.subset <- d %>% filter(variety == 'wt' & root_dry_mass >= 50 & shoot_dry_mass >= 120)
head(d.subset)
## # A tibble: 4 x 7
##   replicate block root_dry_mass shoot_dry_mass trt   fert  variety
##       <dbl> <dbl>         <dbl>          <dbl> <chr> <chr> <chr>  
## 1         1     1            56            132 F10   F10   wt     
## 2         2     1            66            120 F10   F10   wt     
## 3         6     1            66            125 F10   F10   wt     
## 4         8     2            67            122 F10   F10   wt

wt 系統で、「根部乾燥重量が 50 以上」または「地上部乾燥重量が 120 以上」の条件を満たす行を抽出する場合は、次のようにする。

d.subset <- d %>% filter(variety == 'wt', root_dry_mass >= 50 | shoot_dry_mass >= 120)
# d.subset <- d %>% filter(variety == 'wt' & (root_dry_mass >= 50 | shoot_dry_mass >= 120))
head(d.subset)
## # A tibble: 6 x 7
##   replicate block root_dry_mass shoot_dry_mass trt   fert  variety
##       <dbl> <dbl>         <dbl>          <dbl> <chr> <chr> <chr>  
## 1         1     1            56            132 F10   F10   wt     
## 2         2     1            66            120 F10   F10   wt     
## 3         4     1            43            134 F10   F10   wt     
## 4         5     1            55            119 F10   F10   wt     
## 5         6     1            66            125 F10   F10   wt     
## 6         8     2            67            122 F10   F10   wt

別の例として、処理群が F10 以外の行を抽出するときは次のように ! を使う。

# d.subset <- d %>% filter(!(fert == 'F10'))
d.subset <- d %>% filter(fert != 'F10')
head(d.subset)
## # A tibble: 6 x 7
##   replicate block root_dry_mass shoot_dry_mass trt   fert  variety
##       <dbl> <dbl>         <dbl>          <dbl> <chr> <chr> <chr>  
## 1         1     1            12             45 NH4Cl NH4Cl wt     
## 2         2     1            20             60 NH4Cl NH4Cl wt     
## 3         3     1            21             87 NH4Cl NH4Cl wt     
## 4         4     1            15             57 NH4Cl NH4Cl wt     
## 5         5     1             5             26 NH4Cl NH4Cl wt     
## 6         6     1            18             78 NH4Cl NH4Cl wt

dplyr::arrange 関数

arrange 関数は、与えられた条件に基づいて、行を並べ替える。データに欠損値 NA が含まれる場合は、arrange 関数を使って並べ替えるとき、昇順・降順に関わらず、欠損値 NA は常にデータセットの最下部に並べ替えられる。例えば、rice データに対して、根部乾燥重量に基づいて昇順に並べ替えたい場合は、arrange 関数に列名 root_dry_mass を指定すればよい。

d.subset <- d %>% arrange(root_dry_mass)
head(d.subset)
## # A tibble: 6 x 7
##   replicate block root_dry_mass shoot_dry_mass trt           fert  variety
##       <dbl> <dbl>         <dbl>          <dbl> <chr>         <chr> <chr>  
## 1         7     2             1             35 NH4Cl +ANU843 NH4Cl ANU843 
## 2        10     2             3              5 F10 +ANU843   F10   ANU843 
## 3         2     1             4              6 F10 +ANU843   F10   ANU843 
## 4         3     1             4              3 F10 +ANU843   F10   ANU843 
## 5         1     1             4             22 NH4Cl +ANU843 NH4Cl ANU843 
## 6         5     1             5             26 NH4Cl         NH4Cl wt

根部乾燥重量に基づいて降順に並べ替えたい場合は、desc 関数を利用するか、列名に - をつけるかで並べ替えられる。

# d.subset <- d %>% arrange(-root_dry_mass)
d.subset <- d %>% arrange(desc(root_dry_mass))
head(d.subset)
## # A tibble: 6 x 7
##   replicate block root_dry_mass shoot_dry_mass trt   fert  variety
##       <dbl> <dbl>         <dbl>          <dbl> <chr> <chr> <chr>  
## 1         8     2            67            122 F10   F10   wt     
## 2         2     1            66            120 F10   F10   wt     
## 3         6     1            66            125 F10   F10   wt     
## 4         1     1            56            132 F10   F10   wt     
## 5         5     1            55            119 F10   F10   wt     
## 6        11     2            44             37 F10   F10   wt

次に、根部乾燥重量に関して降順で、地上部乾燥重量に関しては昇順で並べるときは、filter 関数と同様に複数の条件を順に与えればよい。filter 関数に複数の条件を代入した場合は、左側の条件が優先される。

d.subset <- d %>% arrange(desc(root_dry_mass), shoot_dry_mass)
head(d.subset)
## # A tibble: 6 x 7
##   replicate block root_dry_mass shoot_dry_mass trt   fert  variety
##       <dbl> <dbl>         <dbl>          <dbl> <chr> <chr> <chr>  
## 1         8     2            67            122 F10   F10   wt     
## 2         2     1            66            120 F10   F10   wt     
## 3         6     1            66            125 F10   F10   wt     
## 4         1     1            56            132 F10   F10   wt     
## 5         5     1            55            119 F10   F10   wt     
## 6        11     2            44             37 F10   F10   wt

これまでに紹介した select 関数、filter 関数および arrange 関数を組み合わせることで、データセットを柔軟に操作できる。例えば、次のような操作も簡単に行える。

  1. 系統が wt の行を抽出し、
  2. rice データから、処理(fert)、根部乾燥重量(root_dry_mass)、地上部乾燥重量(shoot_dry_mass)の 4 列だけを抽出し
  3. 手順 1-2 で抽出したサブセットを根部乾燥重量に基づいて降順に並べる
wt.subset <- d %>%
              filter(variety == 'wt') %>%
              select(fert, root_dry_mass, shoot_dry_mass) %>%
              arrange(desc(root_dry_mass))
head(wt.subset)
## # A tibble: 6 x 3
##   fert  root_dry_mass shoot_dry_mass
##   <chr>         <dbl>          <dbl>
## 1 F10              67            122
## 2 F10              66            120
## 3 F10              66            125
## 4 F10              56            132
## 5 F10              55            119
## 6 F10              44             37

dplyr::group_by 関数

group_by 関数は、与えられた条件い基づいて、データをいくつかのグループ分けるときに使用する関数である。group_by 関数で処理した結果を print しても、group_by 関数の処理前と処理後とでは見た目的には変わらない。しかし、group_by 関数で処理した後のデータセットには、グループ情報が属性として保存される。例えば、rice データセットに対して、各系統ごとにグループ分けを行う場合は次のようにする。

head(d)
## # A tibble: 6 x 7
##   replicate block root_dry_mass shoot_dry_mass trt   fert  variety
##       <dbl> <dbl>         <dbl>          <dbl> <chr> <chr> <chr>  
## 1         1     1            56            132 F10   F10   wt     
## 2         2     1            66            120 F10   F10   wt     
## 3         3     1            40            108 F10   F10   wt     
## 4         4     1            43            134 F10   F10   wt     
## 5         5     1            55            119 F10   F10   wt     
## 6         6     1            66            125 F10   F10   wt
d.grouped <- d %>% group_by(variety)
head(d.grouped)
## # A tibble: 6 x 7
## # Groups:   variety [1]
##   replicate block root_dry_mass shoot_dry_mass trt   fert  variety
##       <dbl> <dbl>         <dbl>          <dbl> <chr> <chr> <chr>  
## 1         1     1            56            132 F10   F10   wt     
## 2         2     1            66            120 F10   F10   wt     
## 3         3     1            40            108 F10   F10   wt     
## 4         4     1            43            134 F10   F10   wt     
## 5         5     1            55            119 F10   F10   wt     
## 6         6     1            66            125 F10   F10   wt

group_by 関数で追加されたグループ情報を削除したい場合は ungroup 関数を使用する。

d.grouped <- d %>% group_by(variety)
d.ungrouped <- d.grouped %>% ungroup()

dplyr::summarise 関数

summarise 関数はデータの集計を行う関数で、group_by 関数などと一緒に使われることが多い。例えば、rice データセットに対して、各系統ごとに根部乾燥重量および地上部乾燥重量の平均値を求めたい場合は、まず variety 列に基づいてグループ分けを行い、続いて根部乾燥重量および地上部乾燥重量の列に対して集計処理(平均値計算)を行う。

d.massave <- d %>%
                group_by(variety) %>%
                summarise(root_dry_mass_ave = mean(root_dry_mass),
                          shoot_dry_mass_ave = mean(shoot_dry_mass))
head(d.massave)
## # A tibble: 2 x 3
##   variety root_dry_mass_ave shoot_dry_mass_ave
##   <chr>               <dbl>              <dbl>
## 1 ANU843               9.67               41.8
## 2 wt                  26.5                77.3

各系統の各処理群に対して平均を求める場合は、group_by のところに条件を 2 つ書く。

d.massave <- d %>%
                group_by(variety, fert) %>%
                summarise(root_dry_mass_ave = mean(root_dry_mass),
                          shoot_dry_mass_ave = mean(shoot_dry_mass))
head(d.massave)
## # A tibble: 6 x 4
## # Groups:   variety [2]
##   variety fert   root_dry_mass_ave shoot_dry_mass_ave
##   <chr>   <chr>              <dbl>              <dbl>
## 1 ANU843  F10                 6                  7.33
## 2 ANU843  NH4Cl               9.17              46.6 
## 3 ANU843  NH4NO3             13.8               71.5 
## 4 wt      F10                49.5              108.  
## 5 wt      NH4Cl              12.6               50.2 
## 6 wt      NH4NO3             17.3               73.3

summarise の中で使われている mean 関数は R の標準関数である。そのため、欠損地を無視して平均値を求めたい場合は、次のように書けばよい。

d.massave <- d %>%
                group_by(variety, fert) %>%
                summarise(root_dry_mass_ave = mean(root_dry_mass, na.rm = TRUE),
                          shoot_dry_mass_ave = mean(shoot_dry_mass, na.rm = TRUE))
head(d.massave)
## # A tibble: 6 x 4
## # Groups:   variety [2]
##   variety fert   root_dry_mass_ave shoot_dry_mass_ave
##   <chr>   <chr>              <dbl>              <dbl>
## 1 ANU843  F10                 6                  7.33
## 2 ANU843  NH4Cl               9.17              46.6 
## 3 ANU843  NH4NO3             13.8               71.5 
## 4 wt      F10                49.5              108.  
## 5 wt      NH4Cl              12.6               50.2 
## 6 wt      NH4NO3             17.3               73.3

summarise 中で使用する関数を独自に定義することもできる。例えば、四分位範囲(IQR)を求める関数 calc.IQR を独自に定義して、それを summarise 中で使う場合は次のようにする。

calc.IQR <- function(x) {
  q1 <- quantile(x, probs = 0.25)
  q3 <- quantile(x, probs = 0.75)
  iqr <- q3 - q1
  return(iqr)
}

d.massave <- d %>%
                group_by(variety, fert) %>%
                summarise(root_dry_mass_IQR = calc.IQR(root_dry_mass),
                          shoot_dry_mass_IQR = calc.IQR(shoot_dry_mass))
head(d.massave)
## # A tibble: 6 x 4
## # Groups:   variety [2]
##   variety fert   root_dry_mass_IQR shoot_dry_mass_IQR
##   <chr>   <chr>              <dbl>              <dbl>
## 1 ANU843  F10                 2.25                4  
## 2 ANU843  NH4Cl               2.5                23.2
## 3 ANU843  NH4NO3              8                  25.8
## 4 wt      F10                17.8                17.2
## 5 wt      NH4Cl              11                  19.2
## 6 wt      NH4NO3              8                  24

dplyr::mutate 関数

mutate 関数は、既存のデータに新しい列を加えたいときに使用する。例えば、根部乾燥重量と地上部乾燥重量の和を計算して、それを dry_mass 列名で既存のデータに追加し、さらに根部乾燥重量が乾燥重量全体における割合を root_dry_mass_ratio 列名で既存のデータに追加する場合は、次のようにする。

d.new <- d %>% mutate(dry_mass = root_dry_mass + shoot_dry_mass,
                      root_dry_mass_ratio = root_dry_mass / dry_mass)
head(d.new)
## # A tibble: 6 x 9
##   replicate block root_dry_mass shoot_dry_mass trt   fert  variety dry_mass
##       <dbl> <dbl>         <dbl>          <dbl> <chr> <chr> <chr>      <dbl>
## 1         1     1            56            132 F10   F10   wt           188
## 2         2     1            66            120 F10   F10   wt           186
## 3         3     1            40            108 F10   F10   wt           148
## 4         4     1            43            134 F10   F10   wt           177
## 5         5     1            55            119 F10   F10   wt           174
## 6         6     1            66            125 F10   F10   wt           191
## # … with 1 more variable: root_dry_mass_ratio <dbl>

新たに作成した列名だけを新しいデータとしたい場合は mutate 関数の代わりに transmute 関数を使う。この際、既存の列名を残すこともできる。

d.new <- d %>% transmute(variety,
                         dry_mass = root_dry_mass + shoot_dry_mass,
                         root_dry_mass_ratio = root_dry_mass / dry_mass)
head(d.new)
## # A tibble: 6 x 3
##   variety dry_mass root_dry_mass_ratio
##   <chr>      <dbl>               <dbl>
## 1 wt           188               0.298
## 2 wt           186               0.355
## 3 wt           148               0.270
## 4 wt           177               0.243
## 5 wt           174               0.316
## 6 wt           191               0.346

dplyr::inner_join 関数

inner_join 関数は 2 つの表データを内部結合するための関数である。例えば、次のように d1d2 の表を用意し、d1fruit 列と d2fruit 列を参照列として、2 つの表を結合させる際に、次のようにする。ただし、内部結合では、両方の参照列に存在するキーのみに対して、結合が行われる。片方の参照列に存在し、もう片方に存在していないキーのデータは結合されない。

d1 <- dplyr::data_frame(fruit = c('apple', 'banana', 'cherry', 'orange'),
                        weight = c(42, 12, 3, 39))
## Warning: `data_frame()` is deprecated, use `tibble()`.
## This warning is displayed once per session.
d2 <- dplyr::data_frame(fruit = c('apple', 'banana', 'cherry', 'watermelon'),
                        volume = c(481, 436, 38, 3924))

d <- dplyr::inner_join(d1, d2, by = 'fruit')
d
## # A tibble: 3 x 3
##   fruit  weight volume
##   <chr>   <dbl>  <dbl>
## 1 apple      42    481
## 2 banana     12    436
## 3 cherry      3     38

2 つの表データの参照列の名前が異なる時は、by オプションで次のように指定する。

d1 <- dplyr::data_frame(fruit_x = c('apple', 'banana', 'cherry', 'orange'),
                        weight = c(42, 12, 3, 39))
d2 <- dplyr::data_frame(fruit_y = c('apple', 'banana', 'cherry', 'watermelon'),
                        volume = c(481, 436, 38, 3924))

d <- dplyr::inner_join(d1, d2, by = c('fruit_x' = 'fruit_y'))
d
## # A tibble: 3 x 3
##   fruit_x weight volume
##   <chr>    <dbl>  <dbl>
## 1 apple       42    481
## 2 banana      12    436
## 3 cherry       3     38

dplyr::left_join 関数

left_join 関数は 2 つの表データを左外部結合するための関数である。左外部結合では、2 つの表データを結合するとき、左側の表の参照列が基準となって結合が行われる。このため、左側の方の参照列に存在し、右側の方に存在していないキーのデータは、NA で補填される。

d1 <- dplyr::data_frame(fruit = c('apple', 'banana', 'cherry', 'orange'),
                        weight = c(42, 12, 3, 39))
d2 <- dplyr::data_frame(fruit = c('apple', 'banana', 'cherry', 'watermelon'),
                        volume = c(481, 436, 38, 3924))

d <- dplyr::left_join(d1, d2, by = 'fruit')
d
## # A tibble: 4 x 3
##   fruit  weight volume
##   <chr>   <dbl>  <dbl>
## 1 apple      42    481
## 2 banana     12    436
## 3 cherry      3     38
## 4 orange     39     NA

dplyr::right_join 関数

right_join 関数は 2 つの表データを右外部結合するための関数である。右外部結合では、2 つの表データを結合するとき、右側の表の参照列が基準となって結合が行われる。このため、右側の方の参照列に存在し、左側の方に存在していないキーのデータは、NA で補填される。

d1 <- dplyr::data_frame(fruit = c('apple', 'banana', 'cherry', 'orange'),
                        weight = c(42, 12, 3, 39))
d2 <- dplyr::data_frame(fruit = c('apple', 'banana', 'cherry', 'watermelon'),
                        volume = c(481, 436, 38, 3924))

d <- dplyr::right_join(d1, d2, by = 'fruit')
d
## # A tibble: 4 x 3
##   fruit      weight volume
##   <chr>       <dbl>  <dbl>
## 1 apple          42    481
## 2 banana         12    436
## 3 cherry          3     38
## 4 watermelon     NA   3924

dplyr::full_join 関数

full_join 関数は 2 つの表データを外部結合するための関数である。片方の参照列に存在し、もう片方の参照列に存在してないようなキーのデータは NA で補填される。

d1 <- dplyr::data_frame(fruit = c('apple', 'banana', 'cherry', 'orange'),
                        weight = c(42, 12, 3, 39))
d2 <- dplyr::data_frame(fruit = c('apple', 'banana', 'cherry', 'watermelon'),
                        volume = c(481, 436, 38, 3924))

d <- dplyr::full_join(d1, d2, by = 'fruit')
d
## # A tibble: 5 x 3
##   fruit      weight volume
##   <chr>       <dbl>  <dbl>
## 1 apple          42    481
## 2 banana         12    436
## 3 cherry          3     38
## 4 orange         39     NA
## 5 watermelon     NA   3924

tidyr

tidyr はデータフレーム(正確には tibble 型のオブジェクト)の並べ方を展開したり、集約したりする際に利用する関数が多く用意されている。reshape2 パッケージの改良版という位置付けである。

tidyr パッケージの機能を説明するために、iris のデータセットを使用する。このデータセットは、次のように 150 行、5 列からなるデータフレームである。

iris <- read.table('data/iris.txt', header = TRUE, sep = '\t')
head(iris)
##   ID Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1  1          5.1         3.5          1.4         0.2  setosa
## 2  2          4.9         3.0          1.4         0.2  setosa
## 3  3          4.7         3.2          1.3         0.2  setosa
## 4  4          4.6         3.1          1.5         0.2  setosa
## 5  5          5.0         3.6          1.4         0.2  setosa
## 6  6          5.4         3.9          1.7         0.4  setosa

tidyr::gather 関数

gather 関数はデータフレームにを折りたたむときに使う。例えば、雌しべおよび雄しべの長さと幅を attribute として、その値を value として折りたたむときは、次のように行う。

iris.df <- iris %>% gather(`Sepal.Length`, `Sepal.Width`, `Petal.Length`, `Petal.Width`,
                           key = 'attribute', value = 'length')
head(iris.df)
##   ID Species    attribute length
## 1  1  setosa Sepal.Length    5.1
## 2  2  setosa Sepal.Length    4.9
## 3  3  setosa Sepal.Length    4.7
## 4  4  setosa Sepal.Length    4.6
## 5  5  setosa Sepal.Length    5.0
## 6  6  setosa Sepal.Length    5.4

tidyr::spread 関数

折りたたまれたデータフレームを、特定の列に基づいて展開したいときは spread 関数を使用する。

iris.spreaded <- iris.df %>% spread(key = 'attribute', value = 'length')
head(iris.spreaded)
##   ID Species Petal.Length Petal.Width Sepal.Length Sepal.Width
## 1  1  setosa          1.4         0.2          5.1         3.5
## 2  2  setosa          1.4         0.2          4.9         3.0
## 3  3  setosa          1.3         0.2          4.7         3.2
## 4  4  setosa          1.5         0.2          4.6         3.1
## 5  5  setosa          1.4         0.2          5.0         3.6
## 6  6  setosa          1.7         0.4          5.4         3.9

リファレンス

R の便利な機能を紹介している書籍が多数あり、それらが HTML としてウェブサイトで公開されている。tidyverse や ggplot2 についてもっと詳しく知りたい方、データ解析をもっと効率よく行いたい方は、ぜひ、次のウェブ資料を参考してみてください。