統計プログラムRの勉強日記

Rに関して勉強してきたことを紹介します

【R】同じ条件で複数列をフィルタリングする|filter_at / filter_all / filter_if

filter関数応用

はじめに

今回はfilter関数を複数の列に一気に適応するための関数であるfilter_at関数、filter_all関数、filter_if関数の使い方や使い分けを紹介したいと思います。これらの関数はdplyrパッケージに含まれる関数です。 これらを使うと複数の列に対して同一条件でフィルタリングする場合(列Aと列Bが5以下になるようフィルタリングする場合など)に無駄に長いコードを書かなくて良くなりコードの可読性が上がります。

使い方

今回紹介する関数はfilter関数の拡張版のような関数です。ポイントはフィルターを適応する列をどのように選ぶのかです。

今回紹介する3つの関数の特徴や使い分け方は次の通りです。

関数 特徴 使いどころ
filter_all 全ての列にフィルターを適応 列の指定が面倒な時(あまり推奨されない)
filter_at 列名に応じて複数の列にフィルターを適応 位置や名前で列が指定できる
filter_if 列の中身に応じて複数の列にフィルターを適応 列の中身で列を指定できる

図にするとこんな感じのイメージになります。 filter_all, filter_at, filter_if関数のイメージ

またこれらの関数では基本的にヘルパー関数としてall_vars()any_vars()関数を使ってフィルタリング条件を指定します。

all_vars()any_vars()の特徴や使い分けは以下の通りです。

関数 特徴 使いどころ
all_vars 全ての指定された列でフィルタリング条件を満たすものだけ抽出 厳しくフィルタリングをかけたい場合
any_vars 指定された列のいずれかでフィルタリング条件を満たすものは抽出 ゆるくフィルタリングをかけたい場合

この関数の特徴を図にするとこんな感じのイメージになります。 any_var, all_varのイメージ

また今回紹介する関数は複数の列を指定することが前提となっているので、フィルタリング条件の条件式の書き方が変わり、列名を代名詞的な方法として.で表現するという特徴もあります。 これらのことは説明するとややこしいので次の章から具体例をたくさん挙げて紹介します。

具体例

今回はirisデータを用いて具体的なコードを紹介していきたいと思います。

filter_all

filter_all関数はfilter関数を全ての列に適応する関数です。全ての列に条件を適応できる場合にはこれを使うことができます。(文字列型になっている列がある場合に数値フィルターをかける場合などは型の整合性がとれずエラーとなります。) 今回はfilter_all関数についてall_vars()を使うパターンと any_vars()を使うパターンの両方をやってみたいと思います。

まずはirisデータから全ての測定値が2.5以上となっているデータだけ抽出する例を紹介します。

library(dplyr)
data = iris[, 1:4] # 種名以外の測定値だけを取り出す
filter_all(data, all_vars(. >= 2.5))

表示される結果はこんな感じになります(クリックで表示

Sepal.Length Sepal.Width Petal.Length Petal.Width
6.3 3.3 6 2.5
7.2 3.6 6.1 2.5
6.7 3.3 5.7 2.5

見てわかるようにすべての列の値が2.5以上になっています

ちなみにこの関数のイメージは以下の通りです。

次にirisデータから全ての列の中からいずれかの測定値が2.5以上となっているデータだけ抽出する例を紹介します。

library(dplyr)
data = iris[, 1:4] # 種名以外の測定値だけを取り出す
filter_all(data, any_vars(. >= 2.5))

表示される結果の頭10行はこんな感じになります(クリックで表示

Sepal.Length Sepal.Width Petal.Length Petal.Width
5.1 3.5 1.4 0.2
4.9 3 1.4 0.2
4.7 3.2 1.3 0.2
4.6 3.1 1.5 0.2
5 3.6 1.4 0.2
5.4 3.9 1.7 0.4
4.6 3.4 1.4 0.3
5 3.4 1.5 0.2
4.4 2.9 1.4 0.2

こちらでは Sepal.Length や Sepal.Width の値は2.5以上になっていますが、 Petal.Width や Petal.Length の値が2.5以下となっています

filter_at

filter_at関数はfilter関数を列名などで指定した複数の列に適応する関数です。適応したくない列がある場合で列の位置や列名で指定することができそうな場合はこれを使うと良いです。

まずはirisデータの1列目と2列目の値がどちらも4より大きな値になる行を抽出するコードを紹介します。

library(dplyr)
data = iris
filter_at(data, .vars = c(1, 2), .vars_predicate = all_vars(. > 4)) # 列の位置で指定する場合
# 下のコードでも同様のフィルターができます。
# 列名で指定する場合
# filter_at(data, .vars = c("Sepal.Length", "Sepal.Width"), .vars_predicate = all_vars(. > 4))
# selectのヘルパー関数を使う場合
# filter_at(data, .vars = vars(matches("Sepal")), .vars_predicate = all_vars(. > 4))

表示される結果はこんな感じになります(クリックで表示

Sepal.Length Sepal.Width Petal.Length Petal.Width
5.7 4.4 1.5 0.4
5.2 4.1 1.5 0.1
5.5 4.2 1.4 0.2

次にirisデータの1列目と2列目の値のうちどちらかが7.5より大きな値になる行を抽出するコードを紹介します。

library(dplyr)
data = iris
filter_at(data, .vars = c(1, 2), .vars_predicate = any_vars(. > 7.5)) 

表示される結果はこんな感じになります(クリックで表示

Sepal.Length Sepal.Width Petal.Length Petal.Width
7.6 3 6.6 2.1
7.7 3.8 6.7 2.2
7.7 2.6 6.9 2.3
7.7 2.8 6.7 2
7.9 3.8 6.4 2
7.7 3 6.1 2.3

こちらでは Sepal.Length 列は条件を満たしていますが、Sepal.Width 列は条件を満たしていません

filter_if

filter_if関数はfilter関数を列の中身に応じて複数の列に適応する関数です。適応したくない列がある場合に列の内容でフィルターをかける列が指定できそうなときはこの関数を使います。

今回はirisデータから列の中身が数字型になっている全ての列の値が2.5以上になっている行を抽出するコードを紹介します。

library(dplyr)
data = iris
filter_if(data, .predicate = is.numeric, .vars_predicate = all_vars(. >= 2.5))

表示される結果はこんな感じになります(クリックで表示

Sepal.Length Sepal.Width Petal.Length Petal.Width Species
6.3 3.3 6 2.5 virginica
7.2 3.6 6.1 2.5 virginica
6.7 3.3 5.7 2.5 virginica

次に列の中身が数字型になっている列のうちどれかの値が2.5以上になっている行を抽出するコードを紹介します。

library(dplyr)
data = iris
filter_if(data, .predicate = is.numeric, .vars_predicate = any_vars(. >= 2.5))

表示される結果の頭10行はこんな感じになります(クリックで表示

Sepal.Length Sepal.Width Petal.Length Petal.Width Species
5.1 3.5 1.4 0.2 setosa
4.9 3 1.4 0.2 setosa
4.7 3.2 1.3 0.2 setosa
4.6 3.1 1.5 0.2 setosa
5 3.6 1.4 0.2 setosa
5.4 3.9 1.7 0.4 setosa
4.6 3.4 1.4 0.3 setosa
5 3.4 1.5 0.2 setosa
4.4 2.9 1.4 0.2 setosa
4.9 3.1 1.5 0.1 setosa

最後に列の中身がファクター型になっている全ての列で値が versicolorになっている行を抽出するコードを紹介します。

(具体例を紹介するためにこのコードを書いていますが適応する列が1列しかないため普通のfilter関数を使った方がスマートです。)

library(dplyr)
data = iris
filter_if(data, .predicate = is.factor, .vars_predicate = all_vars(. == "versicolor"))
# 今回の場合は普通のfilter関数を使った方がスマート(対象列が1列しかないため)
# filter(data, Species == "versicolor")

表示される結果の頭10行はこんな感じになります(クリックで表示

Sepal.Length Sepal.Width Petal.Length Petal.Width Species
7 3.2 4.7 1.4 versicolor
6.4 3.2 4.5 1.5 versicolor
6.9 3.1 4.9 1.5 versicolor
5.5 2.3 4 1.3 versicolor
6.5 2.8 4.6 1.5 versicolor
5.7 2.8 4.5 1.3 versicolor
6.3 3.3 4.7 1.6 versicolor
4.9 2.4 3.3 1 versicolor
6.6 2.9 4.6 1.3 versicolor
5.2 2.7 3.9 1.4 versicolor

まとめ

今回はfilter関数の発展版としてfilter_allfilter_atfilter_if関数を紹介しました。覚えておくとコードを簡単にできるので頭に入れておくと良いかもしれません。