R dplyr 对仅通过其字符串名称已知的列进行操作
R dplyr operate on a column known only by its string name
我正在努力使用 R 中的 dplyr
对数据框的列进行编程,这些列仅以其字符串名称为人所知。我知道最近对 dplyr
进行了更新以支持 quosures 等,我已经在此处查看了我认为是新 "Programming with dplyr" 文章的相关组件:http://dplyr.tidyverse.org/articles/programming.html。但是,我还是做不到我想做的。
我的情况是我只通过字符串名称知道数据框的列名。因此,我不能在函数内调用 dplyr
时使用非标准评估,甚至不能在列名可能在 运行 之间更改的脚本中使用非标准评估,因为我无法对未引用的内容进行硬编码(即 "bare")列名。我想知道如何解决这个问题,我猜我忽略了一些新的 quoting/unquoting 语法。
例如,假设我有定义数据分布的截止百分位数的用户输入。用户可以 运行 使用任何百分位数 he/she 想要的代码,并且百分位数 he/she 选择将更改输出。在分析中,中间数据框中的一列是用所使用的百分位数名称创建的;因此,此列的名称会根据用户输入的截止百分位数而变化。
下面是一个最小的例子来说明。我想用截止百分位数的各种值调用该函数。我希望名为 MPGCutoffs
的数据框有一个根据所选截止分位数命名的列(这目前在下面的代码中有效),我想稍后对该列名称进行操作。由于这个列名的通用性,我在写函数的时候只能根据输入的pctCutoff
来知道,所以我需要一种在只知道[=定义的字符串的情况下对其进行操作的方法16=],它遵循基于 pctCutoff
.
值的预定义模式
userInput_prob1 <- 0.95
userInput_prob2 <- 0.9
# Function to get cars that have the "best" MPG
# fuel economy, where "best" is defined by the
# percentile cutoff passed to the function.
getBestMPG <- function( pctCutoff ){
# Define new column name to hold the MPG percentile cutoff.
probColName <- paste0('P', pctCutoff*100)
# Compute the MPG percentile cutoff by number of gears.
MPGCutoffs <- mtcars %>%
dplyr::group_by( gear ) %>%
dplyr::summarize( !!probColName := quantile(mpg, pctCutoff) )
# Filter mtcars with only MPG values above cutoffs.
output <- mtcars %>%
dplyr::left_join( MPGCutoffs, by='gear' ) %>%
dplyr::filter( mpg > !!probColName ) #****This doesn't run; this is where I'm stuck
# Return filtered data.
return(output)
}
best_1 <- getBestMPG( userInput_prob1 )
best_2 <- getBestMPG( userInput_prob2 )
dplyr::filter()
语句是我无法正确到达 运行 的地方。我试过:
dplyr::filter( mpg > probColName )
- 没有错误,但没有返回任何行。
dplyr::filter( mpg > !!probColName )
- 没有错误,但没有返回任何行。
我也见过这样的例子,我可以将 quo(P95)
之类的东西传递给函数,然后在对 dplyr::filter()
的调用中取消引用它;我已经让它工作了,但它并没有解决我的问题,因为它需要在函数外部对变量名进行硬编码。例如,如果我这样做并且用户传递的百分位数是 0.90,那么对 dplyr::filter()
的调用将失败,因为创建的列名为 P90
而不是 P95
.
如有任何帮助,我们将不胜感激。我希望有一个我忽略的简单解决方案。
如果您在字符串(又名字符向量)中有一个列名并且您想将它与 tidyeval 一起使用,那么您可以使用 rlang::sym()
来隐藏它。只是改变
dplyr::filter( mpg > !!rlang::sym(probColName) )
它应该可以工作。这取自这个 github 问题的建议:https://github.com/tidyverse/rlang/issues/116
用起来还是可以的
dplyr::summarize( !!probColName := quantile(mpg, pctCutoff) )
因为在动态设置参数名称时,您只需要字符串而不是未引用的符号。
这是 Hadley 在 MrFlick 的回答 (https://github.com/tidyverse/rlang/issues/116) 中提到的 post 评论中的替代解决方案。使用基数 R 中的 as.name()
代替 rlang::sym()
,您仍然需要取消对它的引用。也就是说,以下也有效:
dplyr::filter( mpg > !!as.name(probColName) )
我正在努力使用 R 中的 dplyr
对数据框的列进行编程,这些列仅以其字符串名称为人所知。我知道最近对 dplyr
进行了更新以支持 quosures 等,我已经在此处查看了我认为是新 "Programming with dplyr" 文章的相关组件:http://dplyr.tidyverse.org/articles/programming.html。但是,我还是做不到我想做的。
我的情况是我只通过字符串名称知道数据框的列名。因此,我不能在函数内调用 dplyr
时使用非标准评估,甚至不能在列名可能在 运行 之间更改的脚本中使用非标准评估,因为我无法对未引用的内容进行硬编码(即 "bare")列名。我想知道如何解决这个问题,我猜我忽略了一些新的 quoting/unquoting 语法。
例如,假设我有定义数据分布的截止百分位数的用户输入。用户可以 运行 使用任何百分位数 he/she 想要的代码,并且百分位数 he/she 选择将更改输出。在分析中,中间数据框中的一列是用所使用的百分位数名称创建的;因此,此列的名称会根据用户输入的截止百分位数而变化。
下面是一个最小的例子来说明。我想用截止百分位数的各种值调用该函数。我希望名为 MPGCutoffs
的数据框有一个根据所选截止分位数命名的列(这目前在下面的代码中有效),我想稍后对该列名称进行操作。由于这个列名的通用性,我在写函数的时候只能根据输入的pctCutoff
来知道,所以我需要一种在只知道[=定义的字符串的情况下对其进行操作的方法16=],它遵循基于 pctCutoff
.
userInput_prob1 <- 0.95
userInput_prob2 <- 0.9
# Function to get cars that have the "best" MPG
# fuel economy, where "best" is defined by the
# percentile cutoff passed to the function.
getBestMPG <- function( pctCutoff ){
# Define new column name to hold the MPG percentile cutoff.
probColName <- paste0('P', pctCutoff*100)
# Compute the MPG percentile cutoff by number of gears.
MPGCutoffs <- mtcars %>%
dplyr::group_by( gear ) %>%
dplyr::summarize( !!probColName := quantile(mpg, pctCutoff) )
# Filter mtcars with only MPG values above cutoffs.
output <- mtcars %>%
dplyr::left_join( MPGCutoffs, by='gear' ) %>%
dplyr::filter( mpg > !!probColName ) #****This doesn't run; this is where I'm stuck
# Return filtered data.
return(output)
}
best_1 <- getBestMPG( userInput_prob1 )
best_2 <- getBestMPG( userInput_prob2 )
dplyr::filter()
语句是我无法正确到达 运行 的地方。我试过:
dplyr::filter( mpg > probColName )
- 没有错误,但没有返回任何行。
dplyr::filter( mpg > !!probColName )
- 没有错误,但没有返回任何行。
我也见过这样的例子,我可以将 quo(P95)
之类的东西传递给函数,然后在对 dplyr::filter()
的调用中取消引用它;我已经让它工作了,但它并没有解决我的问题,因为它需要在函数外部对变量名进行硬编码。例如,如果我这样做并且用户传递的百分位数是 0.90,那么对 dplyr::filter()
的调用将失败,因为创建的列名为 P90
而不是 P95
.
如有任何帮助,我们将不胜感激。我希望有一个我忽略的简单解决方案。
如果您在字符串(又名字符向量)中有一个列名并且您想将它与 tidyeval 一起使用,那么您可以使用 rlang::sym()
来隐藏它。只是改变
dplyr::filter( mpg > !!rlang::sym(probColName) )
它应该可以工作。这取自这个 github 问题的建议:https://github.com/tidyverse/rlang/issues/116
用起来还是可以的
dplyr::summarize( !!probColName := quantile(mpg, pctCutoff) )
因为在动态设置参数名称时,您只需要字符串而不是未引用的符号。
这是 Hadley 在 MrFlick 的回答 (https://github.com/tidyverse/rlang/issues/116) 中提到的 post 评论中的替代解决方案。使用基数 R 中的 as.name()
代替 rlang::sym()
,您仍然需要取消对它的引用。也就是说,以下也有效:
dplyr::filter( mpg > !!as.name(probColName) )