Non-standard eval in dplyr::mutate

2019-05-11 06:14发布

In theory this should work, as I've read the tidyverse guide on NSE, but it throws me an error as seen in the bottom of this example. Why is this? I understand how to do a simple quasiquotation of an object, but I do not understand how to evaluate a fraction of two quasiquoted objects. Can anyone help with this?

    tmp <- structure(list(qa11a = structure(c(1616, 7293, 1528, 1219, 2049, 286),
                                            label = "Total voters removed from Nov. 2008 to Nov. 2010",
                                            class = c("labelled","numeric")),
                          state_abbv = c("AL", "AL", "AL", "AL", "AL", "AL"),
                          fipscode = c("0100100000", "0100300000", "0100500000",
                                       "0100700000", "0100900000", "0101100000"),
                          qa1a = structure(c(34727, 114952, 16450, 12239, 31874, 7650),
                                           label = "Total registered & eligible to vote November 2010",
                                           class = c("labelled", "numeric")),
                          reg.pct = structure(c(0.0465343968669911, 0.0634438722249287,
                                                0.092887537993921, 0.0995996404935044,
                                                0.0642843697057163, 0.0373856209150327),
                                              label = "Total voters removed from Nov. 2008 to Nov. 2010",
                                              class = c("labelled", "numeric")),
                          precleared = c(1, 1, 1, 1, 1, 1),
                          year = c(2010, 2010, 2010, 2010, 2010, 2010),
                          shelby = c(0, 0, 0, 0, 0, 0), 
                          pres = c(FALSE, FALSE, FALSE, FALSE, FALSE, FALSE)),
                      .Names = c("qa11a", "state_abbv", "fipscode", "qa1a",
                                 "reg.pct", "precleared", "year", "shelby", "pres"),
                      row.names = c(NA, -6L),
                      class = c("tbl_df", "tbl", "data.frame"))

    require(tidyverse)
    require(rlang)

    upper="qa11a"
    lower="qa1a"
    pct.name="rej.reg"

    pct.reg <- quo_name(enquo(pct.name))
    upper <- enquo(upper)
    lower <- enquo(lower)

    h <- tmp %>%
        mutate(!! pct.reg := (!!upper)/(!!lower))

    #> Error in mutate_impl(.data, dots): Evaluation error: non-numeric argument to binary operator.

1条回答
一夜七次
2楼-- · 2019-05-11 06:47

We can convert the string to symbol and then evaluate

tmp %>% 
   mutate(!! pct.name := (!! sym(upper)/(!! sym(lower))))
# A tibble: 6 x 10
#  qa11a state_abbv fipscode     qa1a reg.pct precleared  year shelby pres  rej.reg
#  <dbl> <chr>      <chr>       <dbl>   <dbl>      <dbl> <dbl>  <dbl> <lgl>   <dbl>
#1  1616 AL         0100100000  34727  0.0465       1.00  2010      0 F      0.0465
#2  7293 AL         0100300000 114952  0.0634       1.00  2010      0 F      0.0634
#3  1528 AL         0100500000  16450  0.0929       1.00  2010      0 F      0.0929
#4  1219 AL         0100700000  12239  0.0996       1.00  2010      0 F      0.0996
#5  2049 AL         0100900000  31874  0.0643       1.00  2010      0 F      0.0643
#6   286 AL         0101100000   7650  0.0374       1.00  2010      0 F      0.0374

when we apply enquo on a string, it is converting to a quosure with quotes

enquo(upper)
# <quosure>
#  expr: ^"qa11a"
#  env:  empty

Instead of converting from a string, it could be easier to do

upper <- quo(qalla)
lower <- quo(qala)

In the OP's code, calling enquo i.e. converting to quosure on a string object will result in string quosure and that is not intended

upper <- "qa11a"
lower <- "qa1a"
enquo(upper)
#<quosure>
#  expr: ^"qa11a"
#  env:  empty

We can compare it to

upper <- quo(qa11a)
lower <- quo(qa1a)
upper
# <quosure>
#  expr: ^qalla
#  env:  global

and executing it

tmp %>% 
     mutate(!! pct.name := (!! upper)/ (!! lower))
# A tibble: 6 x 10
#  qa11a state_abbv fipscode     qa1a reg.pct precleared  year shelby pres  rej.reg
#  <dbl> <chr>      <chr>       <dbl>   <dbl>      <dbl> <dbl>  <dbl> <lgl>   <dbl>
#1  1616 AL         0100100000  34727  0.0465       1.00  2010      0 F      0.0465
#2  7293 AL         0100300000 114952  0.0634       1.00  2010      0 F      0.0634
#3  1528 AL         0100500000  16450  0.0929       1.00  2010      0 F      0.0929
#4  1219 AL         0100700000  12239  0.0996       1.00  2010      0 F      0.0996
#5  2049 AL         0100900000  31874  0.0643       1.00  2010      0 F      0.0643
#6   286 AL         0101100000   7650  0.0374       1.00  2010      0 F      0.0374
查看更多
登录 后发表回答