【问题标题】:R: Conditional evaluation of expressions given as strings as values for a dplyr mutateR:以字符串形式给出的表达式的条件评估,作为 dplyr mutate 的值
【发布时间】:2018-10-22 12:52:58
【问题描述】:

我正在尝试使用 case_when 执行 dplyr::mutate() 以在从字符串片段组装的各种公式之间进行选择。但是,在引用并随后取消引用它们之前,我显然没有将字符串正确转换为表达式。我尝试了七八种方法,都没有成功。

从字符串组装表达式的原因是我有大量变量组,它们的名称仅在后缀不同,例如,用于区分名义变量或通货膨胀调整后的美元。我使用 case_when 是因为相似的变量在不同年份有不同的名称,有时还有不同的聚合结构。

这是一个非常简单的例子:

bus_inc <- function(tb, suffix) {
  bus1     <- quo(paste0("incbus", suffix, " + ",  "incfarm", suffix, collapse = ""))
  bus2     <- quo(paste0("incbus2", suffix, " + ",  "incfarm", suffix, collapse = ""))
  bus3     <- quo(paste0("incbus", suffix, " + ",  "incfarm2", suffix, collapse = ""))
  out      <- mutate(tb, bus = case_when((year < 1968) ~ UQ(bus1),
                                   ((year > 1967) & (year < 1976)) ~ UQ(bus2),
                                   (year > 1975) ~ UQ(bus3)))
  out
}

数据:

incbus_99     <-   1:56
incfarm_99   <-  57:112
incbus2_99   <-  incbus_99 + 0.5
incfarm2_99 <-  incfarm_99 * 10
year <- 1962:2017
test_tb <- tibble(year, incbus_99, incfarm_99, incbus2_99, incfarm2_99)

my_test <- bus_inc(tb  = test_tb, suffix = "_99")
my_test

bus 的值在 1962 年应该是 58,在 1968 年应该是 70.5。

我发现许多地方建议使用 parse(text="my_string") 作为将字符串转换为表达式的一种方式,例如 Martin Maechler 的早期example (2002)。但我也发现很多地方说永远不要这样做,例如财富 106 强和最近来自 Martin Maechler 的example。我认为强大的 Maechler 博士对他宝贵提供的解决方案的强烈否定是强有力的证据,表明这不是一个好主意,但我不理解他提出的替代方案,因为它们似乎对字符串进行评估。

【问题讨论】:

  • 你可以做例如rlang::parse_expr(stringr::str_glue("incbus{suffix} + incfarm{suffix}"))。但是其他一些可能很有意义的事情是通过将数据重新整形为“长格式”来完全摆脱后缀列,这样后缀携带的信息将变成一个新列。

标签: r dplyr type-conversion rlang tidyeval


【解决方案1】:

也许使用sym()expr() 的组合(您还需要使用as.numeric,因为不一致的类型会在case_when 中引发错误)...

bus_inc <- function(tb, suffix) {
  bus1 <- expr(!!sym(paste0('incbus', suffix)) + !!sym(paste0('incfarm', suffix)))
  bus2 <- expr(!!sym(paste0('incbus2', suffix)) + !!sym(paste0('incfarm', suffix)))
  bus3 <- expr(!!sym(paste0('incbus', suffix)) + !!sym(paste0('incfarm2', suffix)))
  mutate(tb, bus = case_when(year < 1968 ~ as.numeric(!!bus1),
                             year > 1967 & year < 1976 ~ as.numeric(!!bus2),
                             year > 1975 ~ as.numeric(!!bus3)))
}

library(dplyr)

incbus_99     <-   1:56
incfarm_99   <-  57:112
incbus2_99   <-  incbus_99 + 0.5
incfarm2_99 <-  incfarm_99 * 10
year <- 1962:2017
test_tb <- tibble(year, incbus_99, incfarm_99, incbus2_99, incfarm2_99)

bus_inc(tb  = test_tb, suffix = "_99")

# # A tibble: 56 x 6
#     year incbus_99 incfarm_99 incbus2_99 incfarm2_99   bus
#    <int>     <int>      <int>      <dbl>       <dbl> <dbl>
#  1  1962         1         57        1.5         570  58  
#  2  1963         2         58        2.5         580  60  
#  3  1964         3         59        3.5         590  62  
#  4  1965         4         60        4.5         600  64  
#  5  1966         5         61        5.5         610  66  
#  6  1967         6         62        6.5         620  68  
#  7  1968         7         63        7.5         630  70.5
#  8  1969         8         64        8.5         640  72.5
#  9  1970         9         65        9.5         650  74.5
# 10  1971        10         66       10.5         660  76.5
# # ... with 46 more rows

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多