【发布时间】:2019-07-21 13:02:39
【问题描述】:
我期待我可以使用rlang 包中的准引用机制,例如!! 和quo_name(),以在mutate() 和ifelse() 函数内取消引用程序名称。但是,它并没有像我预期的那样工作,如下所示。它没有在mutate() 调用中解析ifelse() 中数据框范围内的名称值,而是仅解析参数的字符值。我能够使用基本函数get() 来做我想做的事。但是,我一定会混淆某些东西,并且正在寻找如何在 rlang/quasiquotation 世界中做到这一点。感谢您的解释和帮助。
suppressPackageStartupMessages(library(tidyverse))
df <- tibble(x=c(1, NA_integer_, 3), y=101:103)
print(df)
#> # A tibble: 3 x 2
#> x y
#> <dbl> <int>
#> 1 1 101
#> 2 NA 102
#> 3 3 103
# Expected behavior
df %>%
mutate(z = ifelse(is.na(x), y, x))
#> # A tibble: 3 x 3
#> x y z
#> <dbl> <int> <dbl>
#> 1 1 101 1
#> 2 NA 102 102
#> 3 3 103 3
# Similar question seemed to be posted here:
# From: https://community.rstudio.com/t/trouble-with-creating-column-names-from-a-passed-argument-in-function/7819/3
# I expect same output as above, but instead, the column `x` gets filled with the name of the column, not appropriate value.
v_colname <- "x"
df %>%
mutate(z := ifelse(is.na(!!v_colname), y, !!v_colname)) %>%
print()
#> # A tibble: 3 x 3
#> x y z
#> <dbl> <int> <chr>
#> 1 1 101 x
#> 2 NA 102 x
#> 3 3 103 x
# Tried variant with `quo_name()`, same unexpected result:
df %>%
mutate(z := ifelse(is.na(!!quo_name(v_colname)), y, !!quo_name(v_colname)))
#> # A tibble: 3 x 3
#> x y z
#> <dbl> <int> <chr>
#> 1 1 101 x
#> 2 NA 102 x
#> 3 3 103 x
# This works, but I assume I am missing something with quasiquotation semantics:
df %>%
mutate(z := ifelse(is.na(get(v_colname)), y, get(v_colname)))
#> # A tibble: 3 x 3
#> x y z
#> <dbl> <int> <dbl>
#> 1 1 101 1
#> 2 NA 102 102
#> 3 3 103 3
# Session info
sessionInfo()
#> R version 3.5.2 (2018-12-20)
#> Platform: x86_64-w64-mingw32/x64 (64-bit)
#> Running under: Windows 10 x64 (build 16299)
#>
#> Matrix products: default
#>
#> locale:
#> [1] LC_COLLATE=English_United States.1252
#> [2] LC_CTYPE=English_United States.1252
#> [3] LC_MONETARY=English_United States.1252
#> [4] LC_NUMERIC=C
#> [5] LC_TIME=English_United States.1252
#>
#> attached base packages:
#> [1] stats graphics grDevices utils datasets methods base
#>
#> other attached packages:
#> [1] bindrcpp_0.2.2 forcats_0.3.0 stringr_1.3.1 dplyr_0.7.8
#> [5] purrr_0.2.5 readr_1.3.1 tidyr_0.8.2 tibble_2.0.1
#> [9] ggplot2_3.1.0 tidyverse_1.2.1
#>
#> loaded via a namespace (and not attached):
#> [1] Rcpp_1.0.0 cellranger_1.1.0 plyr_1.8.4 pillar_1.3.1
#> [5] compiler_3.5.2 highr_0.7 bindr_0.1.1 tools_3.5.2
#> [9] digest_0.6.18 lubridate_1.7.4 jsonlite_1.6 evaluate_0.12
#> [13] nlme_3.1-137 gtable_0.2.0 lattice_0.20-38 pkgconfig_2.0.2
#> [17] rlang_0.3.1 cli_1.0.1 yaml_2.2.0 haven_2.0.0
#> [21] xfun_0.4 withr_2.1.2 xml2_1.2.0 httr_1.4.0
#> [25] knitr_1.21 hms_0.4.2 generics_0.0.2 grid_3.5.2
#> [29] tidyselect_0.2.5 glue_1.3.0 R6_2.3.0 fansi_0.4.0
#> [33] readxl_1.2.0 rmarkdown_1.11 modelr_0.1.2 magrittr_1.5
#> [37] backports_1.1.3 scales_1.0.0 htmltools_0.3.6 rvest_0.3.2
#> [41] assertthat_0.2.0 colorspace_1.4-0 utf8_1.1.4 stringi_1.2.4
#> [45] lazyeval_0.2.1 munsell_0.5.0 broom_0.5.1 crayon_1.3.4
由reprex package (v0.2.1) 于 2019 年 2 月 27 日创建
【问题讨论】:
-
如果你取消引用一个字符值,你只是插入一个字符值。观察
expr(is.na(!!v_colname))和expr(is.na(!!sym(v_colname)))之间的区别。确保在需要时使用符号,而不是字符值。 (使用library(rlang)) -
谢谢。我错过了这样一个事实,即取消引用引用字符串的名称确实只是返回了字符串。我没有仔细阅读文档,而是研究了示例
df %>% select(!!v_colname),假设由于它在此示例中正常工作,!!隐式转换为符号。我有一种感觉,如果我在那里替换一个字符串,这不会起作用,并且当我这样做时必须使用select_()。 -
这是有道理的。
select的不同寻常之处在于它同时接受字符和符号。但其他大多数功能都比较挑剔。