web-dev-qa-db-ja.com

文字列名でデータフレームをフィルター処理する(dplyr内)

データフレームがあり、「this」列または「that」列のいずれかによって、2つの方法のいずれかでフィルター処理したい。列名を変数として参照できるようにしたいと思います。変数で列名を参照するにはどうすればよいですか(dplyrで)。

library(dplyr)
df <- data.frame(this = c(1, 2, 2), that = c(1, 1, 2))
df
#   this that
# 1    1    1
# 2    2    1
# 3    2    2
df %>% filter(this == 1)
#   this that
# 1    1    1

しかし、変数columnを使用して「this」または「that」のいずれかを保持し、columnの値が何であってもフィルタリングしたいとします。どちらも as.symbolおよびgetは他のコンテキストで機能しますが、これは機能しません。

column <- "this"
df %>% filter(as.symbol(column) == 1)
# [1] this that
# <0 rows> (or 0-length row.names)
df %>% filter(get(column) == 1)
# Error in get("this") : object 'this' not found

columnの値を列名にするにはどうすればよいですか?

24
William Denton

現在のdplyrヘルプファイルから(私による強調):

dplyrは、アンダーバーが末尾に付いた各動詞のツインバージョンを提供するために使用されていました。これらのバージョンには標準評価(SE)のセマンティクスがありました。NSE動詞のようにコードで引数を取るのではなく、値で引数を取りました。彼らの目的は、dplyrでプログラムできるようにすることでした。ただし、dplyrは整然とした評価セマンティクスを使用するようになりました。 NSE動詞はまだ引数をキャプチャしますが、これらの引数の一部の引用符を外すことができます。これにより、NSE動詞による完全なプログラミングが可能になります。したがって、下線付きのバージョンは不要になりました。

unquotingが正確に意味するものは、ビネットで学ぶことができます Programming with dplyr 。これは、関数UQ()によって、または 構文糖 として!!。今あなたのような状況があります-!!は、単一の!

あなたの例に適用されます:

library(dplyr)
df <- data.frame(this = c(1, 2, 2),
                 that = c(1, 1, 2))
column <- "this"

df %>% filter(UQ(as.name(column)) == 1)
#   this that
# 1    1    1

しかし、not

df %>% filter(!!as.name(column) == 1)
# [1] this that
# <0 Zeilen> (oder row.names mit Länge 0)

構文糖!!いくつかの余分な丸括弧を追加すると、想定どおりに再び機能します(提案について Martijn vd Voort に感謝します)。

df %>% filter((!!as.name(column)) == 1)
#   this that
# 1    1    1

または、2つの比較オペランドを交換するだけの場合(ヒントの carand に感謝):

df %>% filter(1 == !!as.name(column))
#   this that
# 1    1    1
30
Salim B

get()を一緒に使用することは避けます。この状況では、特にプログラミングをしている場合は非常に危険だと思われます。未評価の呼び出しまたは貼り付けられた文字列を使用できますが、filter_()の代わりにfilter()を使用する必要があります。

_df <- data.frame(this = c(1, 2, 2), that = c(1, 1, 2))
column <- "this"
_

オプション1-未評価の呼び出しを使用:

yを_1_としてハードコーディングできますが、ここではyとして表示し、式の値を簡単に変更する方法を示します。

_expr <- lazyeval::interp(quote(x == y), x = as.name(column), y = 1)
## or 
## expr <- substitute(x == y, list(x = as.name(column), y = 1))
df %>% filter_(expr)
#   this that
# 1    1    1
_

オプション2-paste()を使用(そして明らかに簡単に):

_df %>% filter_(paste(column, "==", 1))
#   this that
# 1    1    1
_

これら2つのオプションの主な点は、filter_()の代わりにfilter()を使用する必要があることです。実際、私が読んだことから、dplyrを使用してプログラミングしている場合は、常に*_()関数を使用する必要があります。

この投稿を参考資料として使用しました: 関数引数rとしての文字列 、およびdplyrバージョン0.3.0.2を使用しています。

24
Rich Scriven

リチャードのソリューションに関しては、コラムがキャラクターならそれを追加したいだけです。 shQuoteを追加して、文字値でフィルタリングできます。

たとえば、使用できます

df %>% filter_(paste(column, "==", shQuote("a")))

複数のフィルターがある場合は、pastecollapse = "&"を指定できます。

df %>$ filter_(paste(c("column1","column2"), "==", shQuote(c("a","b")), collapse = "&"))
7
StatCC

最新のdplyrバージョンの別のソリューションを次に示します。

df <- data.frame(this = c(1, 2, 2),
                 that = c(1, 1, 2))
column <- "this"

df %>% filter(.[[column]] == 1)

#  this that
#1    1    1
1
paul_dg

またはfilter_at

library(dplyr)
df %>% 
   filter_at(vars(column), any_vars(. == 1))
1
akrun

上記で説明したサリムBと同様ですが、わずかな変更があります。

df %>% filter(1 == !!as.name(column))

つまり、!!それ以外は次のように動作します

!!(as.name(column)==1)
0
carand