Search code examples
rdplyrrlangtidyeval

tidy evaluation cannot work in function in R


Context

I am learning tidy evaluation on this website, And I see an example:

x <- sym("height")

expr(transmute(starwars, bmi = mass / (!! x)^2))
#> transmute(starwars, bmi = mass/(height)^2)

transmute(starwars, bmi = mass / (!! x)^2)
#> # A tibble: 87 x 1
#>     bmi
#>   <dbl>
#> 1  26.0
#> 2  26.9
#> 3  34.7
#> 4  33.3
#> # ... with 83 more rows

Then, I imitated the above example in my own code using sym and !!, but it reported an error.

library(survival)
library(rms)
data(cancer)

x = sym('meal.cal')

expr(cph(Surv(time, status) ~ rcs(!! x), data = lung))
# cph(Surv(time, status) ~ rcs(meal.cal), data = lung)

cph(Surv(time, status) ~ rcs(!!x), data = lung)
# Error in !x : invalid argument type

Question

Why do I use sym and !! in my code will report an error and how to fix it.

Is it because of the rcs().


Solution

  • We can use rlang::inject() to splice arguments with !! into functions that usually don't support tidy evaluation. This saves us from using eval(expr(...)) and also answers your question why we don't need rlang::inject() with dplyr::transmute(). The latter already supports tidy evaluation while cph() does not.

    library(survival)
    library(rms)
    data(cancer)
    
    x = sym('meal.cal')
    
    rlang::inject(cph(Surv(time, status) ~ rcs(!!x), data = lung))
    #> Frequencies of Missing Values Due to Each Variable
    #> Surv(time, status)           meal.cal 
    #>                  0                 47 
    #> 
    #> Cox Proportional Hazards Model
    #>  
    #>  cph(formula = Surv(time, status) ~ rcs(meal.cal), data = lung)
    #>  
    #>  
    #>                          Model Tests    Discrimination    
    #>                                                Indexes    
    #>  Obs        181    LR chi2      0.72    R2       0.004    
    #>  Events     134    d.f.            4    R2(4,181)0.000    
    #>  Center -0.3714    Pr(> chi2) 0.9485    R2(4,134)0.000    
    #>                    Score chi2   0.76    Dxy      0.048    
    #>                    Pr(> chi2) 0.9443                      
    #>  
    #>              Coef    S.E.   Wald Z Pr(>|Z|)
    #>  meal.cal    -0.0006 0.0013 -0.48  0.6299  
    #>  meal.cal'    0.0007 0.0051  0.14  0.8860  
    #>  meal.cal''   0.0010 0.0261  0.04  0.9682  
    #>  meal.cal''' -0.0132 0.0676 -0.19  0.8456  
    #> 
    

    Without tidy evaluation we can stay in base R and use eval(bquote(...)) and splice x with .(x).

    library(survival)
    library(rms)
    data(cancer)
    
    x = sym('meal.cal')
    
    eval(bquote(cph(Surv(time, status) ~ rcs(.(x)), data = lung)))
    #> Frequencies of Missing Values Due to Each Variable
    #> Surv(time, status)           meal.cal 
    #>                  0                 47 
    #> 
    #> Cox Proportional Hazards Model
    #>  
    #>  cph(formula = Surv(time, status) ~ rcs(meal.cal), data = lung)
    #>  
    #>  
    #>                          Model Tests    Discrimination    
    #>                                                Indexes    
    #>  Obs        181    LR chi2      0.72    R2       0.004    
    #>  Events     134    d.f.            4    R2(4,181)0.000    
    #>  Center -0.3714    Pr(> chi2) 0.9485    R2(4,134)0.000    
    #>                    Score chi2   0.76    Dxy      0.048    
    #>                    Pr(> chi2) 0.9443                      
    #>  
    #>              Coef    S.E.   Wald Z Pr(>|Z|)
    #>  meal.cal    -0.0006 0.0013 -0.48  0.6299  
    #>  meal.cal'    0.0007 0.0051  0.14  0.8860  
    #>  meal.cal''   0.0010 0.0261  0.04  0.9682  
    #>  meal.cal''' -0.0132 0.0676 -0.19  0.8456  
    #> 
    

    Created on 2022-09-26 by the reprex package (v2.0.1)