dplyr::filterの再確認

## dplyr::filterの基礎

`dplyr::filter`はレコードをフィルタリングして必要なレコードを残すという関数です。`dplyr`パッケージに組み込まれていますので,使うためには`dplyr`を読み込む必要があります:


```r
library(dplyr)
#>  
#>  Attaching package: 'dplyr'
#>  The following objects are masked from 'package:stats':
#>  
#>      filter, lag
#>  The following objects are masked from 'package:base':
#>  
#>      intersect, setdiff, setequal, union
```


### 使い方

```
filter(.data, ...)
```

`.data`

: 対象となるデータセット。

`...`

: .dataに含まれる変数で定義された論理式。

### 留意事項

関数のヘルプドキュメントに以下のような留意事項がありました:

- データセットのrownamesは黙って削除される
    - もし残したかったら`tibble::rownames_to_column`を実行しといてね
- group_byしたデータセットの場合,うまく最適化されてない
    - filter処理する際はグループ化する前,もしくは`ungroup`してからね

## 実例

サンプルのデータセットを準備します:


```r
d <- data.frame(x0 = 1:10,
                x1 = 11:20,
                s = sample(c("kosaki", "chitoge", "marika"), 10, replace = TRUE),
                row.names = letters[1:10]
                )
d
#>    x0 x1       s
#>  a  1 11  marika
#>  b  2 12  kosaki
#>  c  3 13 chitoge
#>  d  4 14 chitoge
#>  e  5 15  marika
#>  f  6 16  kosaki
#>  g  7 17 chitoge
#>  h  8 18  marika
#>  i  9 19  kosaki
#>  j 10 20 chitoge
```


### 基本的な考え方

filterは,要するに**`...`引数に`TRUE`もしくは`FALSE`の論理値ベクトルを与えればOK**です。実際に直接指定することはないでしょうが,以下のコードでちゃんと動きます:


```r
f <- c(TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, TRUE, FALSE, FALSE)
filter(d, f)
#>    x0 x1       s
#>  1  1 11  marika
#>  2  2 12  kosaki
#>  3  3 13 chitoge
#>  4  7 17 chitoge
#>  5  8 18  marika
```

ただし,この論理値ベクトルは行数と同一である必要があり,異なる場合エラーを返します。エラーが出ない特別な場合として,ベクトル長が1(要するに`TRUE`または`FALSE`がひとつだけ)がありますが,実質意味はないでしょう:


```r
filter(d, TRUE)
#>    x0 x1       s
#>  a  1 11  marika
#>  b  2 12  kosaki
#>  c  3 13 chitoge
#>  d  4 14 chitoge
#>  e  5 15  marika
#>  f  6 16  kosaki
#>  g  7 17 chitoge
#>  h  8 18  marika
#>  i  9 19  kosaki
#>  j 10 20 chitoge
```

フィルターが全くかからない,あるいはレコードが空っぽになる,というときはこういうケースに陥っていることもあるかと思います。

### 数値フィルタ

まずは単一条件についてです。


```r
filter(d, x0==4)
#>    x0 x1       s
#>  1  4 14 chitoge
filter(d, x0!=4)
#>    x0 x1       s
#>  1  1 11  marika
#>  2  2 12  kosaki
#>  3  3 13 chitoge
#>  4  5 15  marika
#>  5  6 16  kosaki
#>  6  7 17 chitoge
#>  7  8 18  marika
#>  8  9 19  kosaki
#>  9 10 20 chitoge
filter(d, x0<4)
#>    x0 x1       s
#>  1  1 11  marika
#>  2  2 12  kosaki
#>  3  3 13 chitoge
filter(d, x0>=4)
#>    x0 x1       s
#>  1  4 14 chitoge
#>  2  5 15  marika
#>  3  6 16  kosaki
#>  4  7 17 chitoge
#>  5  8 18  marika
#>  6  9 19  kosaki
#>  7 10 20 chitoge
```

このあたりは出力と比較すればすぐにわかるかと思います。

次に複数条件についてです。


```r
filter(d, x0<8 & x1>12)
#>    x0 x1       s
#>  1  3 13 chitoge
#>  2  4 14 chitoge
#>  3  5 15  marika
#>  4  6 16  kosaki
#>  5  7 17 chitoge
filter(d, x0>8 | x1<15)
#>    x0 x1       s
#>  1  1 11  marika
#>  2  2 12  kosaki
#>  3  3 13 chitoge
#>  4  4 14 chitoge
#>  5  9 19  kosaki
#>  6 10 20 chitoge
filter(d, xor(x0<8, x1>12))
#>    x0 x1       s
#>  1  1 11  marika
#>  2  2 12  kosaki
#>  3  8 18  marika
#>  4  9 19  kosaki
#>  5 10 20 chitoge
filter(d, dplyr::between(x0, 3, 7))
#>    x0 x1       s
#>  1  3 13 chitoge
#>  2  4 14 chitoge
#>  3  5 15  marika
#>  4  6 16  kosaki
#>  5  7 17 chitoge
```

`xor(x, y)`は「xかつy」の余事象となります。`dplyr::between`は,その名の通り区間を指定します。指定した範囲の値を含むものとなります。

### 文字列フィルタ

まず完全一致についてです。


```r
filter(d, s=="kosaki")
#>    x0 x1      s
#>  1  2 12 kosaki
#>  2  6 16 kosaki
#>  3  9 19 kosaki
filter(d, s!="chitoge")
#>    x0 x1      s
#>  1  1 11 marika
#>  2  2 12 kosaki
#>  3  5 15 marika
#>  4  6 16 kosaki
#>  5  8 18 marika
#>  6  9 19 kosaki
```

このあたりは数値フィルタと同様です。

次に正規表現を利用した一致条件の指定です。この場合,`stringr::str_ detect`関数が便利です。


```r
library(stringr)
filter(d, str_detect(s, "k"))
#>    x0 x1      s
#>  1  1 11 marika
#>  2  2 12 kosaki
#>  3  5 15 marika
#>  4  6 16 kosaki
#>  5  8 18 marika
#>  6  9 19 kosaki
filter(d, str_detect(s, "^k"))
#>    x0 x1      s
#>  1  2 12 kosaki
#>  2  6 16 kosaki
#>  3  9 19 kosaki
```

`stringr::str_detect(string, pattern)`は`string`で指定した文字列ベクトルから正規表現で`pattern`と一致するものを`TRUE`,それ以外を`FALSE`で返してきます。`grepl`を使うよりも簡単でかつ高速に処理する(はず)なのでこちらをおすすめします。

複数の文字列に一致するor一致しないを指定する方法です。


```r
filter(d, s %in% c("kosaki", "marika"))
#>    x0 x1      s
#>  1  1 11 marika
#>  2  2 12 kosaki
#>  3  5 15 marika
#>  4  6 16 kosaki
#>  5  8 18 marika
#>  6  9 19 kosaki
filter(d, !(s %in% c("kosaki", "marika")))
#>    x0 x1       s
#>  1  3 13 chitoge
#>  2  4 14 chitoge
#>  3  7 17 chitoge
#>  4 10 20 chitoge
```

`%in%`演算子は,**左側の各要素が右側の要素のどれかにマッチするか**を判定して`TRUE`もしくは`FALSE`の論理値ベクトルを返します。逆に右側の要素のどれにもマッチしないものを取り出したい場合,上記のようにします。ただ正直これはスマートなコードではないので,同じ処理をする `%nin%`を定義したり,あるいは実装したパッケージもあります。個人的にはbaseに組み込んでほしいところなのですが…。一応定義するとしたら,こういう感じでOKです:


```r
'%nin%' <- function(x, y) !(x %in% y)
filter(d, s %nin% c("kosaki", "chitoge"))
#>    x0 x1      s
#>  1  1 11 marika
#>  2  5 15 marika
#>  3  8 18 marika
```


### NA処理

ちょcっとデータセットを変更します:


```r
d_withNA <- d <- data.frame(x0 = 1:10,
                x1 = 11:20,
                s = sample(c("kosaki", "chitoge", NA), 10, replace = TRUE),
                row.names = letters[1:10]
                )
d_withNA
#>    x0 x1       s
#>  a  1 11    <NA>
#>  b  2 12  kosaki
#>  c  3 13  kosaki
#>  d  4 14    <NA>
#>  e  5 15  kosaki
#>  f  6 16 chitoge
#>  g  7 17  kosaki
#>  h  8 18 chitoge
#>  i  9 19    <NA>
#>  j 10 20    <NA>
```

この場合,このような処理が可能です:


```r
filter(d_withNA, is.na(s))
#>    x0 x1    s
#>  1  1 11 <NA>
#>  2  4 14 <NA>
#>  3  9 19 <NA>
#>  4 10 20 <NA>
filter(d_withNA, !is.na(s))
#>    x0 x1       s
#>  1  2 12  kosaki
#>  2  3 13  kosaki
#>  3  5 15  kosaki
#>  4  6 16 chitoge
#>  5  7 17  kosaki
#>  6  8 18 chitoge
```

`is.na`は「NAか否か」を判定してTRUEあるいはFALSEを返してきます。なのでこの場合sに`NA`があるレコードを抽出してきます。そのため,`!is.na(s)`と否定することでsがNAではないレコードを抽出してくるようになります[^1]。

[^1]: 欠損値への対応としては，tidyrパッケージにも便利な関数が用意してあります。[こちら](http://qiita.com/kazutan/items/ab81958994426e67e017#drop_na-replace_na-fill)にまとめてますので参照してください。

このあたりが使えれば,あとは条件を組み合わせることで望むようなレコード抽出ができるようになるでしょう。

**Enjoy!**