在带有 dplyr (!!paste0, {{}}, as.name(), eval(parse(text=)

using a composite to call a variable dynmically in custom build function with dplyr (!!paste0, {{}}, as.name(), eval(parse(text=)

这是以下问题的扩展:, (2) and also asked in the comments to (2) by Mario Reutter

library(dplyr, tidyverse)
string <- c("car", "train", 'bike', 'plain')
speed1 <- runif(4, min = 0, max = 10000)
speed2 <- runif(4, min = 0, max = 10000)
n1  <- sample(1:100, 4)
n1_plus  <- sample(1:100, 4)
n1_minus <- sample(1:100, 4)
n2  <- sample(1:100, 4)
df <- data.frame(string, speed1, speed2, n1, n2, n1_plus, n1_minus)

感谢 akrun's 我可以构建以下函数:

my_fun <- function(dataf, V1, V2){
dataf %>%
dplyr::mutate("{{V1}}_{{V2}}" := paste0(format({{V1}}, big.mark   = ",") ,
  '\n(' , format({{V2}}, big.mark   = ",") , ')'))}

df<-df%>%my_fun(speed1, n1)

使用"{{V1}}_{{V2}}" :=定义的复合名称创建新变量。

但是,我如何在等式右侧调用复合变量名称?例如。将 format({{V2}}, big.mark = ",") 替换为 format('{{V2}}_plus', big.mark = ",")。我试过了(不工作):

my_fun <- function(dataf, V1, V2){
dataf %>%
dplyr::mutate("{{V1}}_{{V2}}_plus" := paste0(format({{V1}}, big.mark   = ",") ,
  '\n(' , format('{{V2}}_plus', big.mark   = ",") , ')'))}

df<-df%>%my_fun(speed1, n1)

期望的输出: 我希望有一个新列 speed1_n1_plus 结合了 speed1n1_plus 的值:

  string   speed1   speed2 n1 n2 n1_plus n1_minus       speed1_n1_plus
1    car 3958.415 1049.172 70 91      25       53 3,958.415\n(25)
2  train 6203.919 8639.160 52 92      14       91 6,203.919\n(14)
3   bike 2966.391 2997.303 35 55      46       61 2,966.391\n(46)
4  plain 2755.266 1627.379 98 66       8       49 2,755.266\n( 8)

我只需要对多个具有相似名称的变量进行操作。变量名称是 'core' 名称(在本例中为 'n1'、{{V2}})以及后缀和前缀的组合。我想避免为每个变量名添加额外的参数,因为它只为核心名称添加了一个后缀。

我在尝试:!!paste0, as.name(), eval(parse(text=), ...,这可能在函数外工作,但对我来说不在函数内。

my_fun <- function(dataf, V1, V2){
           dataf %>%
              dplyr::mutate("{{V1}}_{{V2}}_plus" := paste0(format({{V1}}, big.mark   = ","),
                  "\n(", format(!! rlang::sym(paste0(rlang::as_string(ensym(V2)), "_plus")), big.mark  = ","), ")"))}

-测试

df %>%
  my_fun(speed1, n1)
 string   speed1    speed2 n1 n2 n1_plus n1_minus  speed1_n1_plus
1    car 4453.441 3336.7287 92 97      28       56 4,453.441\n(28)
2  train 7718.381  638.5120 82 61       9       13 7,718.381\n( 9)
3   bike 4648.093 4267.8390  7 92      83       29 4,648.093\n(83)
4  plain 3815.145  793.6886 18 56      30       46 3,815.145\n(30)

我同意在 mutate 中的赋值右侧使用变量名会有所帮助。之所以没有实施,是因为您可以通过以更长的格式适当地格式化 data_frame 来更有效地执行此操作。

对我来说,speed1 & n1speed2 & n2 似乎是成对的。因此,您可以将 df 从包含 4 行(每辆车 类型 ,即汽车、火车等)转换为 8 行(每辆车 实例 ,即 car1、car2 等)。

在您的示例中,以这种更长的格式构建 data_frame 会更容易,但由于您可能必须使用指定格式的数据库,让我们重新格式化(注意:这非常乏味因为一些信息存储在变量 names 中,需要转换回单个单元格):

df_long = df %>% pivot_longer(-string) %>% #expand on everything but the column "string" (super long format but we need this to grab the information from the column names)
  mutate(number = gsub("\D+", "", name), name = gsub("\d+", "", name)) #separate the numbers from the variable names

#separate speed and everything starting with "n" and get them into a wider format
df_n = df_long %>% filter(grepl("^n", name)) %>% pivot_wider(names_from=name)
df_rest = df_long %>% filter(grepl("^n", name)==F) %>% pivot_wider(names_from=name)

df_tidy = full_join(df_rest, df_n) #join the data frames together
View(df_tidy) #take a look how the df looks differently now (including explicit NAs since n2_plus and n2_minus don't exist in your example)

现在您可以简单地执行此操作以获得您想要的结果:

df_tidy = df_tidy %>% mutate(result = paste0(format(speed, big.mark=","), "\n(", format(n_plus, big.mark=","), ")"))

注意:选择更长的格式可能有意义,这样 nn_plusn_minus 不是不同的列,而是在另一列中编码 n_kind 因子水平为“标准”、“加”和“减”。但我不能从你的例子中判断。