按字符列名称过滤数据(在dplyr中)

Wil*_*ton 26 r dplyr

我有一个数据框,想要以两种方式之一过滤它,通过列"this"或列"that".我希望能够将列名称称为变量.如何(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
Run Code Online (Sandbox Code Playgroud)

但是说我想使用变量column来保存"this"或"that",并过滤任何值的值column.双方as.symbolget在其他环境中工作,但不是这个:

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
Run Code Online (Sandbox Code Playgroud)

如何将值column转换为列名?

Sal*_*m B 32

从当前的dplyr帮助文件(由我强调):

dplyr曾经提供每个动词的双重版本,后缀为下划线.这些版本具有标准评估(SE)语义:它们不是通过代码(如NSE动词)接受参数,而是通过值来获取参数.他们的目的是使用dplyr进行编程成为可能.但是,dplyr现在使用整洁的评估语义.NSE动词仍然捕获它们的参数,但您现在可以取消引用这些参数的一部分.这提供了NSE动词的完全可编程性.因此,强调版本现在是多余的.

使用dplyr编程的插图中可以学到什么不相称的确切含义.它是通过函数或语法糖来实现的.现在有一些情况 - 比如你的情况 - 只有前者才能正常工作,因为它可以与单身相撞."this"columndplyr::filter()column

适用于您的示例:

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

df %>% filter(UQ(as.symbol(column)) == 1)
#   this that
# 1    1    1
Run Code Online (Sandbox Code Playgroud)

不是:

df %>% filter(!!as.symbol(column) == 1)
# [1] this that
# <0 Zeilen> (oder row.names mit Länge 0)
Run Code Online (Sandbox Code Playgroud)

symbol如果你要么添加一些额外的圆括号(感谢Martijn vd Voort的建议),语法糖会再次起作用:

df %>% filter((!!as.symbol(column)) == 1)
#   this that
# 1    1    1
Run Code Online (Sandbox Code Playgroud)

或者,如果您只是交换两个比较操作数(感谢提示的carand):

df %>% filter(1 == !!as.symbol(column))
#   this that
# 1    1    1
Run Code Online (Sandbox Code Playgroud)

  • 对于后一种情况,您可以使用一些额外的圆括号 `df %&gt;% filter((!!as.name(column)) == 1)` (2认同)

Ric*_*ven 24

我会避免get()一起使用.在这种情况下,这似乎很危险,特别是如果你正在编程的话.您可以使用未评估的调用或粘贴的字符串,但您需要使用filter_()而不是filter().

df <- data.frame(this = c(1, 2, 2), that = c(1, 1, 2))
column <- "this"
Run Code Online (Sandbox Code Playgroud)

选项1 - 使用未评估的电话:

你可以硬编码y1,但在这里我告诉它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
Run Code Online (Sandbox Code Playgroud)

选项2 - 使用paste()(并且显然更容易):

df %>% filter_(paste(column, "==", 1))
#   this that
# 1    1    1
Run Code Online (Sandbox Code Playgroud)

这两个选项的主要内容是我们需要使用filter_()而不是filter().事实上,根据我的阅读,如果你正在编程,dplyr你应该总是使用这些*_()功能.

我使用这篇文章作为一个有用的参考:字符串作为函数参数r,我使用的是dplyr版本0.3.0.2.

  • 对于旧版本的`dpylr`,这是一个很好的答案,但不推荐使用下划线函数,因此下面@Salim-B 的答案更好。 (2认同)

pau*_*_dg 9

这是最新 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
Run Code Online (Sandbox Code Playgroud)


Sta*_*tCC 7

关于理查德的解决方案,只想添加一下,如果你的列是字符.您可以添加shQuote按字符值过滤.

例如,您可以使用

df %>% filter_(paste(column, "==", shQuote("a")))
Run Code Online (Sandbox Code Playgroud)

如果你有多个过滤器,你可以指定collapse = "&"paste.

df %>$ filter_(paste(c("column1","column2"), "==", shQuote(c("a","b")), collapse = "&"))
Run Code Online (Sandbox Code Playgroud)


Pho*_* Mu 6

执行此操作的最新方法是使用my.data.frame %>% filter(.data[[myName]] == 1),其中myName是包含列名称的环境变量。