Help us understand the problem. What is going on with this article?

dplyr の select() の引数に指定可能なバリエーションまとめ #rstatsj

More than 5 years have passed since last update.

福島真太朗『データ分析プロセス』を読んでいると、dplyrselect() の使い方で知らないものが載っていた。
調べてみると、select() は引数に様々なバリエーションを受け付けることができることを知ったので、ここにまとめておく。

これらのカラム選択方法は summarise_each(), mutate_each() においても全く同様である。
さらに、tidyr パッケージの各種関数(gather()など)に対しても同じようにして使える。

1. 全コード

一覧性のために、最初に全コードを載せておく。以降のセクションでは一つずつ実行結果を含めて解説する。

R
# データの準備 ------------------------------------------------------------------
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 データを使用する。

R
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() の基本的な使い方は、次のようになる。

R
select(data, year)
結果
  year
1 2013
2 2013
3 2013

データから year カラムだけを取り出した。
複数のカラムを取り出したいときは、次のようにする。

R
select(data, year, month, day)
結果
  year month day
1 2013    12  15
2 2013     7  17
3 2013     3   2

カラムがデータ上で連続している場合は、次のような書き方ができる。

R
select(data, year:day)
結果
  year month day
1 2013    12  15
2 2013     7  17
3 2013     3   2

データから特定のカラムを取り除きたいときは、次のようにマイナス記号を付ける。

R
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

連続したカラムを取り除くには、括弧を付けた上でマイナスを付ける。

R
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

カラム番号を指定して取り出すこともできる。

R
select(data, 1, 2, 3)
select(data, 1:3)
結果
  year month day
1 2013    12  15
2 2013     7  17
3 2013     3   2

ここからは少し高度になる。

連続したカラムを一旦取り出し、その中から特定のカラムを除去するということも、次のように書けばできる。

R
select(data, year:day, -month)
結果
  year day
1 2013  15
2 2013  17
3 2013   2

連続したカラムを取り除くが、その中で必要なカラムだけ残すことも同様にしてできる。

R
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

カラム番号を使った次の書き方も全く同様の結果になる。(※結果は省略)

R
select(data, 1:3, -2)
select(data, -(1:3), 2)

3. 選択ユーティリティー関数

dplyrselect() の引数の中だけで使える、選択ユーティリティー関数というものがある。
(※選択ユーティリティー関数は、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() は、カラム名が指定された文字列から始まるものだけを取り出す。

R
select(data, starts_with("arr"))
結果
  arr_time arr_delay
1     2322         1
2      936       -28
3     1800         0

ignore.case 引数は大文字と小文字を区別するかどうかを指定するもので、デフォルトでは区別しない(TRUE)。

ends_with() は、カラム名が指定された文字列で終わるものだけを取り出す。

R
select(data, ends_with("time"))
結果
  dep_time arr_time air_time
1     2124     2322       88
2      651      936      306
3     1636     1800      103

contains() は、カラム名が指定された文字列を含むものだけを取り出す。

R
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() は、カラム名が指定された正規表現に一致するものだけを取り出す。

R
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() はカラム名に番号が振られている場合に便利である。
データのカラム名を x1x16 に変更したものを作り、それに対して実行してみる。

R
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 までのものを取り出すことができた。
カラム名の数字は、連続している必要はない。

R
select(data2, num_range("x", c(9, 11)))
結果
      x9 x11
1 N801UA EWR
2 N194DN JFK
3 N475WN LGA

num_range()width 引数は、カラム名が x01 のように 0 でパディングされている場合に便利である。
これもカラム名を x01x16 に変更したデータに対して実行してみる。

R
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() は次のような場合にエラーとなる。

R
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() を使えば、意図通りの動きになる。

R
select(data, one_of(col_vector))
結果
  year month day
1 2013    12  15
2 2013     7  17
3 2013     3   2

everything() は全てのカラムを選択する。(※結果省略)

R
select(data, everything())

選択ユーティリティー関数を使った場合も、マイナス符号をつけることによって、「それ以外」を選択するという意味になる。

R
select(data, -starts_with("arr"))
R
  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_() 関数が用意されている。(※関数名の最後にアンダーバーが付いていることに注意)
使い方はカラム名を文字列で指定するという点を除いて同じだが、カラム名をベクトルで指定する場合には注意が必要である。

R
select_(data, "year", "month", "day")
結果
  year month day
1 2013    12  15
2 2013     7  17
3 2013     3   2

カラム名をベクトルとして指定する場合、そのベクトルは .dots 引数に与えなければならない。

R
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_() に与えることができる。

R
select_(data, 'year:day')
select_(data, 'year:day', '-month')
select_(data, '-(year:day)')
select_(data, 'starts_with("arr")')
select_(data, '-ends_with("time")')

ただし、この場合も、ベクトルで与えるためには、.dots 引数に与えなければならない。

R
select_(data, .dots = c('starts_with("arr")', '-ends_with("time")'))

5. 参考

hoxo_m
ホクソエム (hoxo_m) は架空のデータ分析者であり、日本の若手のデータ分析者集団のペンネームである。当初このデータ分析者集団は秘密結社として活動し、ホクソエムを一個人として活動させ続けた。
https://blog.hoxo-m.com/
hoxom
Machine Learning and Data Analysis Company for Your Smiles :)
http://hoxo-m.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした