福島真太朗『データ分析プロセス』を読んでいると、dplyr
の select()
の使い方で知らないものが載っていた。
調べてみると、select()
は引数に様々なバリエーションを受け付けることができることを知ったので、ここにまとめておく。
これらのカラム選択方法は summarise_each()
, mutate_each()
においても全く同様である。
さらに、tidyr
パッケージの各種関数(gather()
など)に対しても同じようにして使える。
1. 全コード
一覧性のために、最初に全コードを載せておく。以降のセクションでは一つずつ実行結果を含めて解説する。
# データの準備 ------------------------------------------------------------------
library(dplyr)
library(nycflights13)
set.seed(123)
data <- sample_n(flights, 3)
glimpse(data)
# 基本 ----------------------------------------------------------------------
select(data, year)
select(data, year, month, day)
select(data, year:day)
select(data, -year, -month, -day)
select(data, -(year:day))
select(data, 1, 2, 3)
select(data, 1:3)
select(data, -1, -2, -3)
select(data, -(1:3))
select(data, year:day, -month)
select(data, -(year:day), month)
select(data, 1:3, -2)
select(data, -(1:3), 2)
# 選択ユーティリティー --------------------------------------------------------------
select(data, starts_with("arr"))
select(data, ends_with("time"))
select(data, contains("_"))
select(data, matches("^(dep|arr)_"))
data2 <- data
colnames(data2) <- sprintf("x%d", 1:16)
select(data2, num_range("x", 8:11))
select(data2, num_range("x", c(9, 11)))
data3 <- data
colnames(data3) <- sprintf("x%02d", 1:16)
select(data3, num_range("x", 8:11, width=2))
col_vector <- c("year", "month", "day")
select(data, col_vector)
select(data, one_of(col_vector))
select(data, everything())
select(data, -starts_with("arr"))
# 標準評価(SE) --------------------------------------------------------------------
select_(data, "year", "month", "day")
col_vector <- c("year", "month", "day")
select_(data, .dots = col_vector)
select_(data, 'year:day')
select_(data, 'year:day', '-month')
select_(data, '-(year:day)')
select_(data, 'starts_with("arr")')
select_(data, '-ends_with("time")')
select_(data, .dots = c('starts_with("arr")', '-ends_with("time")'))
2. データの準備
まずはデータを準備する。
福島真太朗『データ分析プロセス』にならって、nycflights13
パッケージの flights
データを使用する。
library(dplyr)
library(nycflights13)
set.seed(123)
data <- sample_n(flights, 3)
glimpse(data)
Variables:
$ year (int) 2013, 2013, 2013
$ month (int) 12, 7, 3
$ day (int) 15, 17, 2
$ dep_time (int) 2124, 651, 1636
$ dep_delay (dbl) -4, -9, 1
$ arr_time (int) 2322, 936, 1800
$ arr_delay (dbl) 1, -28, 0
$ carrier (chr) "UA", "DL", "WN"
$ tailnum (chr) "N801UA", "N194DN", "N475WN"
$ flight (int) 289, 763, 1501
$ origin (chr) "EWR", "JFK", "LGA"
$ dest (chr) "DTW", "LAX", "MKE"
$ air_time (dbl) 88, 306, 103
$ distance (dbl) 488, 2475, 738
$ hour (dbl) 21, 6, 16
$ minute (dbl) 24, 51, 36
year
から minute
までの 16 個のカラムがある。
2. 基本
まず、select()
の基本的な使い方は、次のようになる。
select(data, year)
year
1 2013
2 2013
3 2013
データから year
カラムだけを取り出した。
複数のカラムを取り出したいときは、次のようにする。
select(data, year, month, day)
year month day
1 2013 12 15
2 2013 7 17
3 2013 3 2
カラムがデータ上で連続している場合は、次のような書き方ができる。
select(data, year:day)
year month day
1 2013 12 15
2 2013 7 17
3 2013 3 2
データから特定のカラムを取り除きたいときは、次のようにマイナス記号を付ける。
select(data, -year, -month, -day)
dep_time dep_delay arr_time arr_delay carrier tailnum flight origin dest air_time distance hour minute
1 2124 -4 2322 1 UA N801UA 289 EWR DTW 88 488 21 24
2 651 -9 936 -28 DL N194DN 763 JFK LAX 306 2475 6 51
3 1636 1 1800 0 WN N475WN 1501 LGA MKE 103 738 16 36
連続したカラムを取り除くには、括弧を付けた上でマイナスを付ける。
select(data, -(year:day))
dep_time dep_delay arr_time arr_delay carrier tailnum flight origin dest air_time distance hour minute
1 2124 -4 2322 1 UA N801UA 289 EWR DTW 88 488 21 24
2 651 -9 936 -28 DL N194DN 763 JFK LAX 306 2475 6 51
3 1636 1 1800 0 WN N475WN 1501 LGA MKE 103 738 16 36
カラム番号を指定して取り出すこともできる。
select(data, 1, 2, 3)
select(data, 1:3)
year month day
1 2013 12 15
2 2013 7 17
3 2013 3 2
ここからは少し高度になる。
連続したカラムを一旦取り出し、その中から特定のカラムを除去するということも、次のように書けばできる。
select(data, year:day, -month)
year day
1 2013 15
2 2013 17
3 2013 2
連続したカラムを取り除くが、その中で必要なカラムだけ残すことも同様にしてできる。
select(data, -(year:day), month)
dep_time dep_delay arr_time arr_delay carrier tailnum flight origin dest air_time distance hour minute month
1 2124 -4 2322 1 UA N801UA 289 EWR DTW 88 488 21 24 12
2 651 -9 936 -28 DL N194DN 763 JFK LAX 306 2475 6 51 7
3 1636 1 1800 0 WN N475WN 1501 LGA MKE 103 738 16 36 3
カラム番号を使った次の書き方も全く同様の結果になる。(※結果は省略)
select(data, 1:3, -2)
select(data, -(1:3), 2)
3. 選択ユーティリティー関数
dplyr
の select()
の引数の中だけで使える、選択ユーティリティー関数というものがある。
(※選択ユーティリティー関数は、summarise_each()
, mutate_each()
, tidyr
の各種関数においても有効)
選択ユーティリティー関数には、以下の 7 つがある。
starts_with(match, ignore.case = TRUE)
ends_with(match, ignore.case = TRUE)
contains(match, ignore.case = TRUE)
matches(match, ignore.case = TRUE)
num_range(prefix, range, width = NULL)
one_of(...)
everything()
使い方を一つずつ見ていこう。
starts_with()
は、カラム名が指定された文字列から始まるものだけを取り出す。
select(data, starts_with("arr"))
arr_time arr_delay
1 2322 1
2 936 -28
3 1800 0
ignore.case
引数は大文字と小文字を区別するかどうかを指定するもので、デフォルトでは区別しない(TRUE
)。
ends_with()
は、カラム名が指定された文字列で終わるものだけを取り出す。
select(data, ends_with("time"))
dep_time arr_time air_time
1 2124 2322 88
2 651 936 306
3 1636 1800 103
contains()
は、カラム名が指定された文字列を含むものだけを取り出す。
select(data, contains("_"))
dep_time dep_delay arr_time arr_delay air_time
1 2124 -4 2322 1 88
2 651 -9 936 -28 306
3 1636 1 1800 0 103
matches()
は、カラム名が指定された正規表現に一致するものだけを取り出す。
select(data, matches("^(dep|arr)_"))
dep_time dep_delay arr_time arr_delay
1 2124 -4 2322 1
2 651 -9 936 -28
3 1636 1 1800 0
num_range()
はカラム名に番号が振られている場合に便利である。
データのカラム名を x1
~x16
に変更したものを作り、それに対して実行してみる。
data2 <- data
colnames(data2) <- sprintf("x%d", 1:16)
select(data2, num_range("x", 8:11))
x8 x9 x10 x11
1 UA N801UA 289 EWR
2 DL N194DN 763 JFK
3 WN N475WN 1501 LGA
num_range("x", 8:11)
と指定することで、カラム名が x8
から x11
までのものを取り出すことができた。
カラム名の数字は、連続している必要はない。
select(data2, num_range("x", c(9, 11)))
x9 x11
1 N801UA EWR
2 N194DN JFK
3 N475WN LGA
num_range()
の width
引数は、カラム名が x01
のように 0 でパディングされている場合に便利である。
これもカラム名を x01
~ x16
に変更したデータに対して実行してみる。
data3 <- data
colnames(data3) <- sprintf("x%02d", 1:16)
select(data3, num_range("x", 8:11, width=2))
x08 x09 x10 x11
1 UA N801UA 289 EWR
2 DL N194DN 763 JFK
3 WN N475WN 1501 LGA
width=2
と指定することで、0 埋めされたカラム名を指定することができた。
one_of()
は、選択したいカラム名を文字列のベクトルとして持っている場合に便利である。
select()
は次のような場合にエラーとなる。
col_vector <- c("year", "month", "day")
select(data, col_vector)
Error: All select() inputs must resolve to integer column positions.
The following do not:
* col_vector
これに対して、one_of()
を使えば、意図通りの動きになる。
select(data, one_of(col_vector))
year month day
1 2013 12 15
2 2013 7 17
3 2013 3 2
everything()
は全てのカラムを選択する。(※結果省略)
select(data, everything())
選択ユーティリティー関数を使った場合も、マイナス符号をつけることによって、「それ以外」を選択するという意味になる。
select(data, -starts_with("arr"))
year month day dep_time dep_delay carrier tailnum flight origin dest air_time distance hour minute
1 2013 12 15 2124 -4 UA N801UA 289 EWR DTW 88 488 21 24
2 2013 7 17 651 -9 DL N194DN 763 JFK LAX 306 2475 6 51
3 2013 3 2 1636 1 WN N475WN 1501 LGA MKE 103 738 16 36
4. 標準評価(Standard Evaluation)
ここまでは、通常の select()
関数を説明したが、select()
は引数として文字列を受け付けない。
普通に使用するぶんにはこれで問題ないのだが、カラム名が文字列ベクトルで与えられる場合などに問題となる。
そのため、文字列を受け付けるバージョンとして select_()
関数が用意されている。(※関数名の最後にアンダーバーが付いていることに注意)
使い方はカラム名を文字列で指定するという点を除いて同じだが、カラム名をベクトルで指定する場合には注意が必要である。
select_(data, "year", "month", "day")
year month day
1 2013 12 15
2 2013 7 17
3 2013 3 2
カラム名をベクトルとして指定する場合、そのベクトルは .dots
引数に与えなければならない。
col_vector <- c("year", "month", "day")
select_(data, .dots = col_vector)
year month day
1 2013 12 15
2 2013 7 17
3 2013 3 2
select()
に通常与えることのできる引数は、文字列にすることで全て select_()
に与えることができる。
select_(data, 'year:day')
select_(data, 'year:day', '-month')
select_(data, '-(year:day)')
select_(data, 'starts_with("arr")')
select_(data, '-ends_with("time")')
ただし、この場合も、ベクトルで与えるためには、.dots
引数に与えなければならない。
select_(data, .dots = c('starts_with("arr")', '-ends_with("time")'))