tidyverse は CRAN パッケージの一つで、tidyr、readr、dplyr、ggplot2 などのパッケージをまとめたパッケージである。 これらのパッケージには、データの読み書き、データの処理、データの可視化などの機能が実装されている。 R の標準関数を使用しても、これらの作業を行うことは可能だが、 tidyverse の機能を使うことで、データの取り扱いが直感的でわかりやすく、 コーディング量も大幅に減らすことができるため、解析に専念できる。 tidyverse の機能を積極的に使用している R は、標準機能の R と区別して、modern R とも呼ばれている。 ここでは、modern R の基本的な使い方を解説していく。 なお、modern R の詳細な使い方に関しては、次の文献を参考にして勉強してくだい。
tidyverse パッケージは CRAN のパッケージとして提供されている。 このパッケージをインストールするには install.packages
関数を使用する。 tidyverse パッケージをインストールすることで、 readr パッケージ、dplyr パッケージ、ggplot2 パッケージ、tidyr パッケージなど も自動的にインストールされる。
install.packages('tidyverse')
tidyverse パッケージの機能を呼び出して使うとき、 他のパッケージと同様に library
関数あるいは require
関数を使う。 tidyverse パッケージを呼び出すと、自動的に dplyr や ggplot2 などのパッケージも呼び出される。
library(tidyverse)
## ── Attaching packages ─────────────────────────────────────────────────────────────────────────────────────── tidyverse 1.3.0 ──
## ✓ ggplot2 3.3.2 ✓ purrr 0.3.4
## ✓ tibble 3.0.3 ✓ dplyr 1.0.1
## ✓ tidyr 1.1.1 ✓ stringr 1.4.0
## ✓ readr 1.3.1 ✓ forcats 0.5.0
## ── Conflicts ────────────────────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
## x dplyr::filter() masks stats::filter()
## x dplyr::lag() masks stats::lag()
tidyverse を呼び出すと、R の標準関数が書き換えられる。 その情報が Conflicts に書かれている。 上の例では、R の標準パッケージ(stats)にある標準関数の filter
関数および lag
関数が、 tidyverse 中の dplyr パッケージの filter
関数および lag
関数にマスク(上書き)されたことを表している。 したがって、tidyverse パッケージを呼び出したあとに、R のプログラムがエラー出るようになったとき、 自分のプログラムで使っている標準関数が、tidyverse の関数によって上書きされていないかを確認するとよい。 上書きされた場合、自分のプログラムに書かれている関数の前に stats::
をつけると R 本来の標準関数が使えるようになる。
x <- c(1.2, 2.4, 3.6, 4.8)
lag(x) # before
stats::lag(x) # after
readr パッケージには、データの読み書きや文字列の処理などの機能が実装されている。 readr が提供している関数は、R の標準関数に比べて、処理速度が速い。 データが大きいときに、データ処理の効率化が期待できる。
readr パッケージの関数を使ってファイルを読み込むには、read_csv
関数あるいは read_tsv
関数を使う。 これらの関数は R の標準関数の read.csv
や read.table
関数とほぼ同じ機能を持つ。 しかし、以下に挙げた何点かにおいて、readr パッケージの関数が優れている。
read_csv
や read_tsv
関数にはお節介な機能がない。
実際の使い方は、次のようになっている。
# CSV file
d <- read_csv('data/rice.csv')
head(d)
# TSV file
d <- read_tsv('data/rice.txt')
head(d)
なお、区切り文字を指定して、テキストファイルからデータを読み込むときは、read_delim
を使う。 このとき、区切り文字を delim
オプションで指定する。
d <- read_delim('data/rice.txt', delim = '\t')
head(d)
ファイル書き出し用の関数には write_csv
、write_tsv
、write_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_number | 文字列中に含まれている数字を数値に変換する。 |
parse_character | 文字列を文字型に変換する。UTF-8 以外の文字列コードから UTF-8 に変換するときに使用する。 |
parse_datetime | 文字列を datetime 型に変換する。 |
parse_date | 文字列を date 型に変換する。 |
parse_time | 文字列を time 型に変換する。 |
文字列を理論型や数値に変換する例。
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
文字列で記載された数値の中に桁区切りとしてカンマが使われることがある。 このように記述された文字列を数値に変換するには、parse_number
関数を使用する。 なお、桁区切りは、国や地域によって異なり、 例えばヨーロッパの多くの国ではピリオドを使い、スイスではシングルクォテーションマークを使っている。 桁区切りがカンマ以外の場合は、grouping_mask
オプションで指定できる。
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
文字コードの変換は parse_character
関数を使う。 次は、Shift-JIS の日本語文字列を UTF-8 の文字列に変換する例である。 Excel で作られた CSV ファイルを解析するときに便利である。
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"
print(y + 20)
## [1] "2019-11-09"
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
dplyr は表データの操作に特化した R のパッケージである。 特定の行あるいは列を抽出したり、抽出したサブセットに対して集計を行ったりするの ような機能が多く実装されている。 dplyr パッケージで提供している各関数は、2 GB 前後までのデータに対応している。 このサイズを超えるような 10〜100 GB 規模のビッグデータなどを取り扱う場合は、 data.table パッケージの使用が推奨される。
dplyr パッケージの関数でデータを扱うとき、データの流れに着目するとわかりやすい。 例えば、d
というデータに対して、 A
処理を行なった後に B
処理を行い、そして、その処理結果を x
に保存したいとき、 データの流れは d
→ A
→ B
→ x
のようになっている。 これを dplyr のルールにしたがって記述すると次のようになる。
d %>% A %>% B -> x
dplyr パッケージでは、d
の内容を関数 A
に流すときに %>%
演算子を使用する。 次に、A
関数で処理した結果を B
関数に流すときも同様に %>%
演算子を使用する。 最後に、関数 B
の処理結果を x
に代入したいから、R の代入演算子(<-
または ->
)を使用する。
データの流れとして上のように記述した方がわかりやすい。 しかし、R のスタンダードな書き方では、変数名を左側に、処理を右側に記述することが一般的である。 そのため、上の例ではエラーなく実行可能なものの、次のように書いた方がより一般的である。
x <- d %>% A %>% B
各関数の説明をあとで解説するが、 例えばファイルからデータを読み取り、variety 列の情報に基づいて、 データ全体を wt と ANU843 のサブセットにグループ分けし、 それぞれのサブセットで root_dry_mass 列の平均を求める処理は、次のように書ける。
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))
## `summarise()` ungrouping output (override with `.groups` argument)
head(variety_ave)
## # A tibble: 2 x 2
## variety mass_ave
## <chr> <dbl>
## 1 ANU843 9.67
## 2 wt 26.5
以下では rice.txt データを使って dplyr の説明を続ける。 このデータの列名やデータの構成を head
や tail
などの関数を使って一度確認しておくとよい。
dplyr パッケージに実装されたデータ操作用の関数を以下の表に示した。 なお、表に示した関数は dplyr パッケージの関数の一部にすぎない。
関数 | 動作 |
---|---|
select | 与えられた条件に基づいて、特定の列を抽出する。 |
filter | 与えられた条件に基づいて、特定の行を抽出する。 |
arrange | 与えられた条件に基づいて、行を並べ替える。 |
group_by | 与えられた条件に基づいて、データセット全体をいくつかのグループに分ける。 |
summarise | 最大値・最小値・平均値を求めるなどのデータの集計を行う。 |
mutate | 既存のデータセットに新しい列を加える。 |
inner_join | 2 つの表データを内部結合させる。 |
left_join | 2 つの表データを左外部結合させる。 |
right_join | 2 つの表データを右外部結合させる。 |
full_join | 2 つの表データを完全外部結合させる。 |
select
関数は、与えられた条件に基づいて、特定の列を抽出する関数である。 例えば rice データセットから、系統(variety)、処理(fert)、根部乾燥重量(root_dry_mass)、 地上部乾燥重量(shoot_dry_mass)の 4 列だけを取り出してサブセットを作成したい場合は、次のようにする。
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 %>% 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_with
、ends_with
、matches
などの関数も使用できる。
filter
関数は与えられた条件に基づいて、特定の行を抽出する関数である。 例えば、根部乾燥重量(root_dry_mass 列)が 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
関数に加えればよい。 例えば、variety 列が wt かつ root_dry_mass 列が 50 以上の行を抽出するには、次のようにする。 複数の条件をカンマで区切ることで、自動的に AND 演算が行われる。
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
条件が 2 以上でも同じように行える。 例えば、「wt 系統」、「根部乾燥重量が 50 以上」、「地上部乾燥重量が 120 以上」の 3 つの条件を 同時に満たす行を抽出する場合は、次のようにする。
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
なお、AND 演算を明記したい場合は、次のようにカンマではなく、&
演算子を使って複数の条件をつなげる。
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
複数の条件に対する理論演算の中で、AND 演算のほかに OR 演算というものもある。 OR 演算の場合は |
演算子を使用する。 例えば、「根部乾燥重量が 50 以上」または「地上部乾燥重量が 120 以上」の条件を満たす行を抽出する場合は、 次のようにする。
d_subset <- d %>% filter(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
AND 演算と OR 演算を組み合わせることで、複雑な抽出条件を作ることができる。 例えば、wt 系統の「根部乾燥重量が 50 以上」または「地上部乾燥重量が 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
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
関数と同様に複数の条件を順に与えればよい。 なお、arrange
関数に複数の条件を代入した場合は、左側の条件が優先されることに注意。 例えば、根部乾燥重量に関して降順で、地上部乾燥重量に関しては昇順で並べるときは、次のように記述する。
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
関数を組み合わせて使うことで、 様々な処理が行えるようになる。 例えば、次のような操作も容易に行える。
wt.subset <- d %>%
filter(variety == 'wt') %>%
select(fert, root_dry_mass, shoot_dry_mass) %>%
arrange(desc(shoot_dry_mass))
head(wt.subset)
## # A tibble: 6 x 3
## fert root_dry_mass shoot_dry_mass
## <chr> <dbl> <dbl>
## 1 F10 43 134
## 2 F10 56 132
## 3 NH4NO3 23 129
## 4 F10 66 125
## 5 F10 67 122
## 6 F10 66 120
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()
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))
## `summarise()` ungrouping output (override with `.groups` argument)
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))
## `summarise()` regrouping output by 'variety' (override with `.groups` argument)
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 の標準関数である。 R 標準の mean
関数では、計算元が値に NA
が含まれると、その平均値の計算結果も NA
となる。 そのため、欠損地を無視して平均値を求めたい場合は、次のように書けばよい。
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))
## `summarise()` regrouping output by 'variety' (override with `.groups` argument)
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))
## `summarise()` regrouping output by 'variety' (override with `.groups` argument)
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
mutate
関数は、既存のデータに新しい列を加えたいときに使う関数である。 例えば、根部乾燥重量(root_dry_mass)と地上部乾燥重量(shoot_dry_mass)の和を計算して、 それを dry_mass 列名で既存のデータに追加する場合は次のように記述する。
d_new <- d %>% mutate(dry_mass = root_dry_mass + shoot_dry_mass)
head(d_new)
## # A tibble: 6 x 8
## 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
mutate
関数の中で、作成した直後の変数を使って、さらに別の計算を行うことができる。 次の例では、まず dry_mass というデータを新規追加し、 そのすぐあとに dry_mass のデータを使って、計算などを行っている。
d_new <- d %>% mutate(dry_mass = root_dry_mass + shoot_dry_mass,
root_dry_mass_ratio = root_dry_mass / dry_mass,
shoot_dry_mass_ratio = shoot_dry_mass / dry_mass)
head(d_new)
## # A tibble: 6 x 10
## 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 2 more variables: root_dry_mass_ratio <dbl>,
## # shoot_dry_mass_ratio <dbl>
新たに作成した列名だけを新しいデータフレーム(tibble)として保存したい場合は、 mutate
関数の代わりに transmute
関数を使う。
d_new <- d %>% transmute(dry_mass = root_dry_mass + shoot_dry_mass,
root_dry_mass_ratio = root_dry_mass / dry_mass,
shoot_dry_mass_ratio = shoot_dry_mass / dry_mass)
head(d_new)
## # A tibble: 6 x 3
## dry_mass root_dry_mass_ratio shoot_dry_mass_ratio
## <dbl> <dbl> <dbl>
## 1 188 0.298 0.702
## 2 186 0.355 0.645
## 3 148 0.270 0.730
## 4 177 0.243 0.757
## 5 174 0.316 0.684
## 6 191 0.346 0.654
inner_join
関数は 2 つの表データを内部結合するための関数である。 例えば、次のように d1
と d2
の表を用意し、 d1
の fruit
列と d2
の fruit
列を参照列として、 2 つの表を結合させる際に、次のようにする。 ただし、内部結合では、両方の参照列に存在するキーのみに対して、結合が行われる。 片方の参照列に存在し、もう片方に存在していないキーの値は結合されない。
d1 <- dplyr::data_frame(fruit = c('apple', 'banana', 'cherry', 'orange'),
weight = c(42, 12, 3, 39))
## Warning: `data_frame()` is deprecated as of tibble 1.1.0.
## Please use `tibble()` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_warnings()` to see where this warning was generated.
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
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
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
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 はデータフレーム(正確には tibble 型のオブジェクト)の並べ方を展開したり、 集約したりする際に利用する関数が多く用意されている。
tidyr パッケージの機能を説明するために、iris のデータセットを使用する。 このデータセットは、次のように 150 行、5 列からなるデータフレームである。
iris <- read_tsv('data/iris.txt')
## Parsed with column specification:
## cols(
## ID = col_double(),
## Sepal.Length = col_double(),
## Sepal.Width = col_double(),
## Petal.Length = col_double(),
## Petal.Width = col_double(),
## Species = col_character()
## )
head(iris)
## # A tibble: 6 x 6
## ID Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 1 5.1 3.5 1.4 0.2 setosa
## 2 2 4.9 3 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 3.6 1.4 0.2 setosa
## 6 6 5.4 3.9 1.7 0.4 setosa
pivot_longer
関数はデータフレームにを折りたたむときに使う。 例えば、花弁(petal)およびがく(sepal)の長さと幅を attribute として、 その値を value として折りたたむときは、次のように記述する。
iris_df <- iris %>% tidyr::pivot_longer(c(Sepal.Length, Sepal.Width, Petal.Length, Petal.Width),
names_to = 'attribute', values_to = 'value')
head(iris_df)
## # A tibble: 6 x 4
## ID Species attribute value
## <dbl> <chr> <chr> <dbl>
## 1 1 setosa Sepal.Length 5.1
## 2 1 setosa Sepal.Width 3.5
## 3 1 setosa Petal.Length 1.4
## 4 1 setosa Petal.Width 0.2
## 5 2 setosa Sepal.Length 4.9
## 6 2 setosa Sepal.Width 3
次のように、-
を付けることで特定の列を取り除いたあとに、 残った列で折りたたむことができる。
iris_df <- iris %>% tidyr::pivot_longer(-c(ID, Species),
names_to = 'attribute', values_to = 'value')
head(iris_df)
## # A tibble: 6 x 4
## ID Species attribute value
## <dbl> <chr> <chr> <dbl>
## 1 1 setosa Sepal.Length 5.1
## 2 1 setosa Sepal.Width 3.5
## 3 1 setosa Petal.Length 1.4
## 4 1 setosa Petal.Width 0.2
## 5 2 setosa Sepal.Length 4.9
## 6 2 setosa Sepal.Width 3
各列の属性が同じであれば(すべての列が数値、あるいはすべての列が文字列ならば)、 次のように everything()
を使うことで、すべての列を折りたたむことができる。 なお、次の例では iris のデータの ID および Species 列は文字列となっているので、 これらの列を除いてから everything()
の例を試している。
iris_df <- iris %>%
dplyr::select(- c(ID, Species)) %>%
tidyr::pivot_longer(everything(),
names_to = 'attribute', values_to = 'value')
head(iris_df)
## # A tibble: 6 x 2
## attribute value
## <chr> <dbl>
## 1 Sepal.Length 5.1
## 2 Sepal.Width 3.5
## 3 Petal.Length 1.4
## 4 Petal.Width 0.2
## 5 Sepal.Length 4.9
## 6 Sepal.Width 3
折りたたまれたデータフレームを、特定の列に基づいて展開したいときは pivot_wider
関数を使用する。 pivot_longer
関数の逆の働きをする関数である。 次は pivot_longer
関数でデータを折りたたんだ後に、pivot_wider
関数で展開する例を示している。
iris_df <- iris %>% tidyr::pivot_longer(c(Sepal.Length, Sepal.Width, Petal.Length, Petal.Width),
names_to = 'attribute', values_to = 'value')
iris_spreaded <- iris_df %>% tidyr::pivot_wider(names_from = 'attribute', values_from = 'value')
head(iris_spreaded)
## # A tibble: 6 x 6
## ID Species Sepal.Length Sepal.Width Petal.Length Petal.Width
## <dbl> <chr> <dbl> <dbl> <dbl> <dbl>
## 1 1 setosa 5.1 3.5 1.4 0.2
## 2 2 setosa 4.9 3 1.4 0.2
## 3 3 setosa 4.7 3.2 1.3 0.2
## 4 4 setosa 4.6 3.1 1.5 0.2
## 5 5 setosa 5 3.6 1.4 0.2
## 6 6 setosa 5.4 3.9 1.7 0.4