ほとんどのtidyr動詞は、インタラクティブなデータ探索を高速かつ流動的にするためにtidy評価を使用する。tidy評価とは、tidyverse全体で使用される非標準の評価の特別なタイプである。ここにいくつかの典型的なtidyrのコードがある。
library(tidyr)
%>%
iris nest(data = !Species)
#> # A tibble: 3 × 2
#> Species data
#> <fct> <list>
#> 1 setosa <tibble [50 × 4]>
#> 2 versicolor <tibble [50 × 4]>
#> 3 virginica <tibble [50 × 4]>
!Species
を使って「 Species
を除くすべての列」と言えば、列名を引用したり ( "Species"
) 、囲んだデータフレームを参照したり ( iris$Species
) する必要がないのは、整頓された評価のおかげである。
tidyrでは、2つの基本的な評価形式が使われている。
tidy selection: drop_na()
, fill()
, pivot_longer()
/ pivot_wider()
, nest()
/ unnest()
, separate()
/ extract()
, および unite()
を選択することができる。 変数を、位置、名前、型に基づいて使用することがでく (例: 1:3
, starts_with("x")
, is.numeric
)。文字どおり、以下のようなテクニックを使うことができる。 dplyr::select()
.
データマスキング。expand()
, crossing()
および nesting()
を参照することができる。 データ変数を環境変数と同じように使う(すなわち
df$myvariable
ではなく my_variable
と書いてみよう)。
ここでは、最も一般的であるため、tidy選択に焦点を当てる。データマスキングについては、dplyrの同等のvignetteで詳しく学ぶことができる。<https://dplyr.tidyverse.org/dev/articles/programming.html>;.パッケージでtidyrのコードを書くときの他の考慮事項については。vignette("in-packages")
を参照してみよう。
tidyrの整然とした評価インターフェースは、対話的な探索のために最適化されていることを指摘した。裏を返せば、これは間接的な使用、すなわち for
ループや関数の内部で作業しているときに、いくつかの課題を追加するということである。この vignette では、そのような課題を克服する方法を紹介する。まず、tidy選択とデータマスキングの基本を説明し、それらを間接的に使用する方法について話し、そして一般的な問題を解決するためのいくつかのレシピを紹介する。
先に進む前に、使用しているtidyrのバージョンを明らかにし、例で使用するための小さなデータセットを作成する。
packageVersion("tidyr")
#> [1] '1.2.0'
<- as_tibble(iris)[c(1, 2, 51, 52, 101, 102), ]
mini_iris
mini_iris#> # A tibble: 6 × 5
#> Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#> <dbl> <dbl> <dbl> <dbl> <fct>
#> 1 5.1 3.5 1.4 0.2 setosa
#> 2 4.9 3 1.4 0.2 setosa
#> 3 7 3.2 4.7 1.4 versicolor
#> 4 6.4 3.2 4.5 1.5 versicolor
#> 5 6.3 3.3 6 2.5 virginica
#> 6 5.8 2.7 5.1 1.9 virginica
tidy選択を使用するすべての関数の下には、 tidyselectパッケージがある。これは、名前、位置、またはタイプによって列を簡単に選択できる、ミニチュアのドメイン固有の言語を提供する。たとえば
select(df, 1)
は最初の列を選択し。select(df, last_col())
は最後の列を選択する。
select(df, c(a, b, c))
は。a
, b
, および c
の列を選択する。
select(df, starts_with("a "))
selects all columns whose name starts with" a“; select(df, ends_with("z "))
selects all columns whose name ends with” z".
select(df, where(is.numeric))
は、すべての数値列を選択する。
詳しくは。?tidyr_tidy_select
を参照。
tidy セレクションは、一般的なタスクを簡単にするが、その代償として、あまり一般的でないタスクを難しくする。中間変数に格納された列の仕様で間接的にtidy selectを使用したい場合、いくつかの新しいツールを学ぶ必要がある。これが出てくる主なケースは3つある。
関数の引数にtidy-selectの指定がある場合、その引数を2重の中括弧で囲んで抱擁しなければならない。
<- function(df, cols) {
nest_egg nest(df, egg = {{ cols }})
}
nest_egg(mini_iris, !Species)
#> # A tibble: 3 × 2
#> Species egg
#> <fct> <list>
#> 1 setosa <tibble [2 × 4]>
#> 2 versicolor <tibble [2 × 4]>
#> 3 virginica <tibble [2 × 4]>
変数名の文字ベクトルがある場合、変数が見つからなかった場合に関数をエラーにするかどうかで。all_of()
または any_of()
を使用する必要がある。これらの関数を使うと、forループや変数名を文字ベクタで受け取る関数を書くことができる。
<- function(df, cols) {
nest_egg nest(df, egg = all_of(cols))
}
<- c("Sepal.Length", "Sepal.Width", "Petal.Length", "Petal.Width")
vars nest_egg(mini_iris, vars)
#> # A tibble: 3 × 2
#> Species egg
#> <fct> <list>
#> 1 setosa <tibble [2 × 4]>
#> 2 versicolor <tibble [2 × 4]>
#> 3 virginica <tibble [2 × 4]>
より複雑なケースでは、直接tidyselectを使用したいだろう。
<- function(df, cols) {
sel_vars ::eval_select(rlang::enquo(cols), df)
tidyselect
}sel_vars(mini_iris, !Species)
#> Sepal.Length Sepal.Width Petal.Length Petal.Width
#> 1 2 3 4
詳しくは。vignette("tidyselect")
。
多くの tidyr 関数は ...
を使っているので、例えば fill(df, x, y, z)
のように簡単に多くの変数を選択することができることに注意。私は今、このアプローチのデメリットはメリットを上回り、このインターフェイスは fill(df, c(x, y, z))
の方がよかったと思われる。列を選択する新しい関数については、引数を1つだけにして。...
を使わないでみよう。