データフレームがあり、「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
の値を列名にするにはどうすればよいですか?
現在の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
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を使用しています。
リチャードのソリューションに関しては、コラムがキャラクターならそれを追加したいだけです。 shQuote
を追加して、文字値でフィルタリングできます。
たとえば、使用できます
df %>% filter_(paste(column, "==", shQuote("a")))
複数のフィルターがある場合は、paste
でcollapse = "&"
を指定できます。
df %>$ filter_(paste(c("column1","column2"), "==", shQuote(c("a","b")), collapse = "&"))
最新の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
またはfilter_at
library(dplyr)
df %>%
filter_at(vars(column), any_vars(. == 1))
上記で説明したサリムBと同様ですが、わずかな変更があります。
df %>% filter(1 == !!as.name(column))
つまり、!!
それ以外は次のように動作します
!!(as.name(column)==1)