使用复合在自定义构建函数中动态调用变量 dplyr (!!paste0, , as.name(), eval(parse(text=)
Posted
技术标签:
【中文标题】使用复合在自定义构建函数中动态调用变量 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=)使用复合在自定义构建函数中动态调用变量 dplyr (!!paste0, , as.name(), eval(parse(text=) 【发布时间】:2021-10-30 08:53:32 【问题描述】:这是对以下问题的延伸:(1)、(2) 并在 cmets 中由Mario Reutter 向(2) 提问。
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的answer我可以构建以下函数:
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
结合来自 speed1
和 n1_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)
我只需要对具有相似名称的多个变量进行操作。变量名称是“核心”名称(在本例中为“n1”,V2
)以及后缀和前缀的组合。我想避免为每个变量名称添加额外的参数,因为它只为核心名称添加了一个后缀。
我正在尝试:!!paste0, as.name(), eval(parse(text=), ...,它可能在函数之外工作,但对我来说不在函数内部。
【问题讨论】:
你是否已经在数据中创建了_plus
_plust
是我之前在数据中创建的后缀示例。可能是_SD
、_skew
、……为什么?我不想改变我以前所做的一切的一般结构,但只有在我必须这样做的情况下。
即类似df$speed1_SD <- 100000
嗯,它是一个数值向量;基本上是数据框中的一列。
我的意思是你在全局环境中有一个名为n1_plus
的向量对象,它不是数据的一部分。您是否希望将该对象创建为列(因为它不是“df”的一部分
【参考方案1】:
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)
【讨论】:
@MsGISRocker 第二个选项会更动态 @MsGISRocker 在您的更新中,我也看到了n1_minus
,它不是在原始数据中创建的。这也是你预期的一部分吗
n1_plus
, n1_minus
, ... 是通过后缀扩展 n1
的变量名称的变量示例。这将在函数中通过后缀扩展变量名称n1
来调用。
@MsGISRocker 是的,但是我发现在您的 globalenv 中创建的那些对象是向量,而不是“df”的一部分。因此,我希望该函数从 globalenv 中选择这些对象并创建为列。如果这是您的意思,请更新帖子
@arkun:我明天再看看,因为我现在该睡觉了。【参考方案2】:
我同意在mutate
内的赋值右侧使用变量名会很有帮助。未实现此功能的原因是您可以通过将data_frame
适当地格式化为更长的格式来更有效地执行此操作。
在我看来,speed1
& n1
和 speed2
& 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=","), ")"))
注意:选择更长的格式可能是有意义的,这样n
、n_plus
和n_minus
不是不同的列,而是在另一个列中编码n_kind
,因子级别为“标准”,“加”和“减”。但我无法从你的例子中判断。
【讨论】:
有趣的想法。我可能会更深入地考虑它。以上是关于使用复合在自定义构建函数中动态调用变量 dplyr (!!paste0, , as.name(), eval(parse(text=)的主要内容,如果未能解决你的问题,请参考以下文章