在字段和值都在变量中的 dplyr 中使用 filter_
Using filter_ in dplyr where both field and value are in variables
我想使用在变量中定义的字段过滤数据帧,select 一个也在变量中的值。说我有
df <- data.frame(V=c(6, 1, 5, 3, 2), Unhappy=c("N", "Y", "Y", "Y", "N"))
fld <- "Unhappy"
sval <- "Y"
我想要的值是 df[df$Unhappy == "Y", ]
。
我已阅读 nse
小插图以尝试使用 filter_
但不太理解。我试过了
df %>% filter_(.dots = ~ fld == sval)
什么也没返回。我得到了我想要的
df %>% filter_(.dots = ~ Unhappy == sval)
但这显然违背了使用变量来存储字段名称的目的。请问有什么线索吗?最终我想使用它,其中 fld
是字段名称的向量,sval
是 fld
.
中每个字段的过滤器值向量
您可以尝试使用 lazyeval
中的 interp
library(lazyeval)
library(dplyr)
df %>%
filter_(interp(~v==sval, v=as.name(fld)))
# V Unhappy
#1 1 Y
#2 5 Y
#3 3 Y
对于多个 key/value 对,我发现这很有效,但我认为应该有更好的方法。
df1 %>%
filter_(interp(~v==sval1[1] & y ==sval1[2],
.values=list(v=as.name(fld1[1]), y= as.name(fld1[2]))))
# V Unhappy Col2
#1 1 Y B
#2 5 Y B
对于这些情况,我发现 base R
选项更容易。例如,如果我们尝试 filter
基于 'fld1' 中的 'key' 变量的行与 'sval1' 中的相应值,一个选项是使用 Map
。我们对数据集 (df1[fld1]
) 进行子集化,并将 FUN (==
) 应用于 df1[f1d1]
的每一列,并在 'sval1' 中使用相应的值,并将 &
与 Reduce
获取可用于 filter
行 'df1'.
的逻辑向量
df1[Reduce(`&`, Map(`==`, df1[fld1],sval1)),]
# V Unhappy Col2
# 2 1 Y B
#3 5 Y B
数据
df1 <- cbind(df, Col2= c("A", "B", "B", "C", "A"))
fld1 <- c(fld, 'Col2')
sval1 <- c(sval, 'B')
这里有一个基于 R
的替代方案,它可能不是很优雅,但它可能具有相当容易理解的好处:
df[df[colnames(df)==fld]==sval,]
# V Unhappy
#2 1 Y
#3 5 Y
#4 3 Y
现在,rlang
0.4.0 为此类用例引入了一种更直观的新方法:
packageVersion("rlang")
# [1] ‘0.4.0’
df <- data.frame(V=c(6, 1, 5, 3, 2), Unhappy=c("N", "Y", "Y", "Y", "N"))
fld <- "Unhappy"
sval <- "Y"
df %>% filter(.data[[fld]]==sval)
#OR
filter_col_val <- function(df, fld, sval) {
df %>% filter({{fld}}==sval)
}
filter_col_val(df, Unhappy, "Y")
可以在 https://www.tidyverse.org/articles/2019/06/rlang-0-4-0/
找到更多信息
上一个答案
对于 dplyr 0.6.0 及更高版本,此代码有效:
packageVersion("dplyr")
# [1] ‘0.7.1’
df <- data.frame(V=c(6, 1, 5, 3, 2), Unhappy=c("N", "Y", "Y", "Y", "N"))
fld <- "Unhappy"
sval <- "Y"
df %>% filter(UQ(rlang::sym(fld))==sval)
#OR
df %>% filter((!!rlang::sym(fld))==sval)
#OR
fld <- quo(Unhappy)
sval <- "Y"
df %>% filter(UQ(fld)==sval)
有关 dplyr
语法的更多信息,请访问 http://dplyr.tidyverse.org/articles/programming.html and the quosure usage in the rlang
package https://cran.r-project.org/web/packages/rlang/index.html。
如果您发现在 dplyr 0.6+ 中掌握非标准评估具有挑战性,Alex Hayes 有一篇关于该主题的精彩文章:https://www.alexpghayes.com/blog/gentle-tidy-eval-with-examples/
原答案
使用 dplyr 0.5.0 及更高版本,可以使用更简单的语法并更接近 @Ricky 最初想要的语法,我也发现它比使用 lazyeval::interp
[=20= 更具可读性]
df %>% filter_(.dots = paste0(fld, "=='", sval, "'"))
# V Unhappy
#1 1 Y
#2 5 Y
#3 3 Y
#OR
df %>% filter_(.dots = glue::glue("{fld}=='{sval}'"))
从 LmW 开始;我个人更喜欢使用 dplyr 管道,其中点在管道之前指定,这样更容易以编程方式使用,比如在过滤器循环中。
dots <- paste0(fld," == '",sval,"'")
df %>% filter_(.dots = dots)
LmW 的示例是正确的,但值是硬编码的。
所以我试图做同样的事情,现在 dplyr 似乎有一个内置功能来解决这个问题。
在此处检查最后一个示例:https://dplyr.tidyverse.org/reference/filter.html
为了简单起见,我也把它粘贴在这里:
# To refer to column names that are stored as strings, use the `.data` pronoun:
vars <- c("mass", "height")
cond <- c(80, 150)
starwars %>%
filter(
.data[[vars[[1]]]] > cond[[1]],
.data[[vars[[2]]]] > cond[[2]]
)
我想使用在变量中定义的字段过滤数据帧,select 一个也在变量中的值。说我有
df <- data.frame(V=c(6, 1, 5, 3, 2), Unhappy=c("N", "Y", "Y", "Y", "N"))
fld <- "Unhappy"
sval <- "Y"
我想要的值是 df[df$Unhappy == "Y", ]
。
我已阅读 nse
小插图以尝试使用 filter_
但不太理解。我试过了
df %>% filter_(.dots = ~ fld == sval)
什么也没返回。我得到了我想要的
df %>% filter_(.dots = ~ Unhappy == sval)
但这显然违背了使用变量来存储字段名称的目的。请问有什么线索吗?最终我想使用它,其中 fld
是字段名称的向量,sval
是 fld
.
您可以尝试使用 lazyeval
interp
library(lazyeval)
library(dplyr)
df %>%
filter_(interp(~v==sval, v=as.name(fld)))
# V Unhappy
#1 1 Y
#2 5 Y
#3 3 Y
对于多个 key/value 对,我发现这很有效,但我认为应该有更好的方法。
df1 %>%
filter_(interp(~v==sval1[1] & y ==sval1[2],
.values=list(v=as.name(fld1[1]), y= as.name(fld1[2]))))
# V Unhappy Col2
#1 1 Y B
#2 5 Y B
对于这些情况,我发现 base R
选项更容易。例如,如果我们尝试 filter
基于 'fld1' 中的 'key' 变量的行与 'sval1' 中的相应值,一个选项是使用 Map
。我们对数据集 (df1[fld1]
) 进行子集化,并将 FUN (==
) 应用于 df1[f1d1]
的每一列,并在 'sval1' 中使用相应的值,并将 &
与 Reduce
获取可用于 filter
行 'df1'.
df1[Reduce(`&`, Map(`==`, df1[fld1],sval1)),]
# V Unhappy Col2
# 2 1 Y B
#3 5 Y B
数据
df1 <- cbind(df, Col2= c("A", "B", "B", "C", "A"))
fld1 <- c(fld, 'Col2')
sval1 <- c(sval, 'B')
这里有一个基于 R
的替代方案,它可能不是很优雅,但它可能具有相当容易理解的好处:
df[df[colnames(df)==fld]==sval,]
# V Unhappy
#2 1 Y
#3 5 Y
#4 3 Y
现在,rlang
0.4.0 为此类用例引入了一种更直观的新方法:
packageVersion("rlang")
# [1] ‘0.4.0’
df <- data.frame(V=c(6, 1, 5, 3, 2), Unhappy=c("N", "Y", "Y", "Y", "N"))
fld <- "Unhappy"
sval <- "Y"
df %>% filter(.data[[fld]]==sval)
#OR
filter_col_val <- function(df, fld, sval) {
df %>% filter({{fld}}==sval)
}
filter_col_val(df, Unhappy, "Y")
可以在 https://www.tidyverse.org/articles/2019/06/rlang-0-4-0/
找到更多信息上一个答案
对于 dplyr 0.6.0 及更高版本,此代码有效:
packageVersion("dplyr")
# [1] ‘0.7.1’
df <- data.frame(V=c(6, 1, 5, 3, 2), Unhappy=c("N", "Y", "Y", "Y", "N"))
fld <- "Unhappy"
sval <- "Y"
df %>% filter(UQ(rlang::sym(fld))==sval)
#OR
df %>% filter((!!rlang::sym(fld))==sval)
#OR
fld <- quo(Unhappy)
sval <- "Y"
df %>% filter(UQ(fld)==sval)
有关 dplyr
语法的更多信息,请访问 http://dplyr.tidyverse.org/articles/programming.html and the quosure usage in the rlang
package https://cran.r-project.org/web/packages/rlang/index.html。
如果您发现在 dplyr 0.6+ 中掌握非标准评估具有挑战性,Alex Hayes 有一篇关于该主题的精彩文章:https://www.alexpghayes.com/blog/gentle-tidy-eval-with-examples/
原答案
使用 dplyr 0.5.0 及更高版本,可以使用更简单的语法并更接近 @Ricky 最初想要的语法,我也发现它比使用 lazyeval::interp
[=20= 更具可读性]
df %>% filter_(.dots = paste0(fld, "=='", sval, "'"))
# V Unhappy
#1 1 Y
#2 5 Y
#3 3 Y
#OR
df %>% filter_(.dots = glue::glue("{fld}=='{sval}'"))
从 LmW 开始;我个人更喜欢使用 dplyr 管道,其中点在管道之前指定,这样更容易以编程方式使用,比如在过滤器循环中。
dots <- paste0(fld," == '",sval,"'")
df %>% filter_(.dots = dots)
LmW 的示例是正确的,但值是硬编码的。
所以我试图做同样的事情,现在 dplyr 似乎有一个内置功能来解决这个问题。
在此处检查最后一个示例:https://dplyr.tidyverse.org/reference/filter.html
为了简单起见,我也把它粘贴在这里:
# To refer to column names that are stored as strings, use the `.data` pronoun:
vars <- c("mass", "height")
cond <- c(80, 150)
starwars %>%
filter(
.data[[vars[[1]]]] > cond[[1]],
.data[[vars[[2]]]] > cond[[2]]
)