【问题标题】:Quasiquotation and ifelse : Unquoting not resolving as expectedQuasiquotation 和 ifelse :取消引用未按预期解决
【发布时间】: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 %&gt;% select(!!v_colname),假设由于它在此示例中正常工作,!! 隐式转换为符号。我有一种感觉,如果我在那里替换一个字符串,这不会起作用,并且当我这样做时必须使用select_()
  • 这是有道理的。 select 的不同寻常之处在于它同时接受字符和符号。但其他大多数功能都比较挑剔。

标签: r rlang


【解决方案1】:

我们可以转换为符号(sym)然后计算(!!

library(dplyr)
df %>%
  mutate(z := ifelse(is.na(!!rlang::sym(v_colname)), y, !! rlang::sym(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

【讨论】:

猜你喜欢
  • 2019-01-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-29
  • 2018-06-06
  • 2021-07-06
  • 1970-01-01
相关资源
最近更新 更多