dplyr::filterの注意点
最近すっかりHadley信者になってしまいデータ加工にもdplyrをよく使っているのだけれど、filterで少し躓いてしまったのでメモ。
まずは{dplyr}と{dtplyr}を読み込む:
library(dplyr) library(dtplyr)
やりたかった処理とは以下のようなもので、irisを例とするとSpeciesごとにfilter内での条件を変えたかった。
> iris %>% + filter(Species == "setosa", Sepal.Length >= 3 | + Species == "versicolor", Sepal.Length >= 1 | + Species == "virginica", Sepal.Length >= 2) %>% tbl_dt() Source: local data table [50 x 5] # tbl_dt [50 × 5] Sepal.Length Sepal.Width Petal.Length Petal.Width Species <dbl> <dbl> <dbl> <dbl> <fctr> 1 5.1 3.5 1.4 0.2 setosa 2 4.9 3.0 1.4 0.2 setosa 3 4.7 3.2 1.3 0.2 setosa 4 4.6 3.1 1.5 0.2 setosa 5 5.0 3.6 1.4 0.2 setosa 6 5.4 3.9 1.7 0.4 setosa 7 4.6 3.4 1.4 0.3 setosa 8 5.0 3.4 1.5 0.2 setosa 9 4.4 2.9 1.4 0.2 setosa 10 4.9 3.1 1.5 0.1 setosa # ... with 40 more rows
しかしこのOutputにはsetosaしか残っておらず、どうやらOR条件("|")以下が評価されていないようなのである。。
{dplyr}のfilterでは"&"もAND条件として使用可能なので、そちらで試してみるとうまく行く。
> iris %>% + filter(Species == "setosa" & Sepal.Length >= 3 | + Species == "versicolor" & Sepal.Length >= 1 | + Species == "virginica" & Sepal.Length >= 2) %>% tbl_dt() Source: local data table [150 x 5] # tbl_dt [150 × 5] Sepal.Length Sepal.Width Petal.Length Petal.Width Species <dbl> <dbl> <dbl> <dbl> <fctr> 1 5.1 3.5 1.4 0.2 setosa 2 4.9 3.0 1.4 0.2 setosa 3 4.7 3.2 1.3 0.2 setosa 4 4.6 3.1 1.5 0.2 setosa 5 5.0 3.6 1.4 0.2 setosa 6 5.4 3.9 1.7 0.4 setosa 7 4.6 3.4 1.4 0.3 setosa 8 5.0 3.4 1.5 0.2 setosa 9 4.4 2.9 1.4 0.2 setosa 10 4.9 3.1 1.5 0.1 setosa # ... with 140 more rows
数値などは一切変えていないが、150行抽出されている。
しかし以下の2つは同じ結果を返すので、","と"&"だけの問題ではなさそう。
# ","でつなぐ > iris %>% + filter(Species == "setosa" , Sepal.Length >= 5) %>% tbl_dt() Source: local data table [30 x 5] # tbl_dt [30 × 5] Sepal.Length Sepal.Width Petal.Length Petal.Width Species <dbl> <dbl> <dbl> <dbl> <fctr> 1 5.1 3.5 1.4 0.2 setosa 2 5.0 3.6 1.4 0.2 setosa 3 5.4 3.9 1.7 0.4 setosa 4 5.0 3.4 1.5 0.2 setosa 5 5.4 3.7 1.5 0.2 setosa 6 5.8 4.0 1.2 0.2 setosa 7 5.7 4.4 1.5 0.4 setosa 8 5.4 3.9 1.3 0.4 setosa 9 5.1 3.5 1.4 0.3 setosa 10 5.7 3.8 1.7 0.3 setosa # ... with 20 more rows
# "&"でつなぐ > iris %>% + filter(Species == "setosa" & Sepal.Length >= 5) %>% tbl_dt() Source: local data table [30 x 5] # tbl_dt [30 × 5] Sepal.Length Sepal.Width Petal.Length Petal.Width Species <dbl> <dbl> <dbl> <dbl> <fctr> 1 5.1 3.5 1.4 0.2 setosa 2 5.0 3.6 1.4 0.2 setosa 3 5.4 3.9 1.7 0.4 setosa 4 5.0 3.4 1.5 0.2 setosa 5 5.4 3.7 1.5 0.2 setosa 6 5.8 4.0 1.2 0.2 setosa 7 5.7 4.4 1.5 0.4 setosa 8 5.4 3.9 1.3 0.4 setosa 9 5.1 3.5 1.4 0.3 setosa 10 5.7 3.8 1.7 0.3 setosa # ... with 20 more rows
"|"も組み合わせて使うと異なる結果が返るのだろうか。
> iris %>% + filter(Species == "setosa" , Sepal.Length >= 5 | Species == "virginica") %>% + tbl_dt() Source: local data table [30 x 5] # tbl_dt [30 × 5] Sepal.Length Sepal.Width Petal.Length Petal.Width Species <dbl> <dbl> <dbl> <dbl> <fctr> 1 5.1 3.5 1.4 0.2 setosa 2 5.0 3.6 1.4 0.2 setosa 3 5.4 3.9 1.7 0.4 setosa 4 5.0 3.4 1.5 0.2 setosa 5 5.4 3.7 1.5 0.2 setosa 6 5.8 4.0 1.2 0.2 setosa 7 5.7 4.4 1.5 0.4 setosa 8 5.4 3.9 1.3 0.4 setosa 9 5.1 3.5 1.4 0.3 setosa 10 5.7 3.8 1.7 0.3 setosa # ... with 20 more rows
> iris %>% + filter(Species == "setosa" & Sepal.Length >= 5 | Species == "virginica") %>% + tbl_dt() Source: local data table [80 x 5] # tbl_dt [80 × 5] Sepal.Length Sepal.Width Petal.Length Petal.Width Species <dbl> <dbl> <dbl> <dbl> <fctr> 1 5.1 3.5 1.4 0.2 setosa 2 5.0 3.6 1.4 0.2 setosa 3 5.4 3.9 1.7 0.4 setosa 4 5.0 3.4 1.5 0.2 setosa 5 5.4 3.7 1.5 0.2 setosa 6 5.8 4.0 1.2 0.2 setosa 7 5.7 4.4 1.5 0.4 setosa 8 5.4 3.9 1.3 0.4 setosa 9 5.1 3.5 1.4 0.3 setosa 10 5.7 3.8 1.7 0.3 setosa # ... with 70 more rows
ちなみにfilter内ではAND/OR条件の優先順位を付けるために括弧を使うことができるが、以下のように","を括弧で括る書き方はエラーとなる:
# ","を括弧でくくるとエラーになる > iris %>% + filter((Species == "setosa" , Sepal.Length >= 5)) %>% Error: unexpected ',' in: "iris %>% filter((Species == "setosa" ,"
# "&"や"|"なら大丈夫 > iris %>% + filter((Species == "setosa" & Sepal.Length >= 5)) %>% + tbl_dt() Source: local data table [30 x 5] # tbl_dt [30 × 5] Sepal.Length Sepal.Width Petal.Length Petal.Width Species <dbl> <dbl> <dbl> <dbl> <fctr> 1 5.1 3.5 1.4 0.2 setosa 2 5.0 3.6 1.4 0.2 setosa 3 5.4 3.9 1.7 0.4 setosa 4 5.0 3.4 1.5 0.2 setosa 5 5.4 3.7 1.5 0.2 setosa 6 5.8 4.0 1.2 0.2 setosa 7 5.7 4.4 1.5 0.4 setosa 8 5.4 3.9 1.3 0.4 setosa 9 5.1 3.5 1.4 0.3 setosa 10 5.7 3.8 1.7 0.3 setosa # ... with 20 more rows > > iris %>% + filter((Species == "setosa" | Sepal.Length >= 5)) %>% + tbl_dt() Source: local data table [148 x 5] # tbl_dt [148 × 5] Sepal.Length Sepal.Width Petal.Length Petal.Width Species <dbl> <dbl> <dbl> <dbl> <fctr> 1 5.1 3.5 1.4 0.2 setosa 2 4.9 3.0 1.4 0.2 setosa 3 4.7 3.2 1.3 0.2 setosa 4 4.6 3.1 1.5 0.2 setosa 5 5.0 3.6 1.4 0.2 setosa 6 5.4 3.9 1.7 0.4 setosa 7 4.6 3.4 1.4 0.3 setosa 8 5.0 3.4 1.5 0.2 setosa 9 4.4 2.9 1.4 0.2 setosa 10 4.9 3.1 1.5 0.1 setosa # ... with 138 more rows
原因が明確になったわけではないが、ひとまずANDの指定には"&"を使ったほうが良さそうだ。