与SAS和STATA中的宏类似,在R中动态创建数据框和变量名

问题描述

一年多来,我一直在努力寻找解决方案,并决定为此写一篇文章。任何帮助,将不胜感激。这是我可以在Stata和SAS中轻松完成的伪代码,但我不知道如何在R中完成。{}是今年dplyr中引入的类似于胶水的运算符, 因此,我将其用作使伪代码起作用的运算符的占位符。

library(tidyverse)
var <- "mpg"
df_name <- "mtcars"

{df_name} %>% count({var})

{df_name}_1 <- {df_name} %>% mutate(.,{var}_1={var}/2)

length({df_name}_1)

应该导致

library(tidyverse)
var <- "mpg"
df_name <- "mtcars"

mtcars %>% count(mpg)

mtcars_1 <- mtcars %>% mutate(.,mpg_1=mpg/2)

length(mtcars_1)

在Stata中,我可以轻松地使用本地或全局宏,如下所示:

local df_name "mtcars"

然后将其引用为`df_name'

在SAS中,我可以使用这样的全局宏来做到这一点:

 %LET df_name=mtcars;

然后像&df_name一样引用它。

请注意,引用这些值在视觉上很容易-无需赋值,获取,括号,大括号等。

两种方法都允许在数据集名称函数,变量等中使用它们。极大地简化了我的代码并节省了很多时间。如何在R中以视觉简洁的方式做到这一点?对于熟悉Stata / SAS的人来说,我的代码应该是可读的(dplyr在这方面太棒了!),太多的评估,将所有内容包装在函数中,用括号赋值只会使他们放弃项目或迫使我改回SAS / Stata。

我尝试了{{}},!!,enquo,sym和NSE的所有组合,但仍然不知道如何以视觉上简单的方式进行这项工作。在dplyr管道中,终于有了一些变量名称解决方法,而对数据框和基本R没有任何解决方法

在此问题上的任何帮助,我将非常感谢!早在2009年,我就遇到了R的问题,并放弃了R,直到我不得不在2019年回来,但仍然找不到解决此问题的简便方法

解决方法

R是一种功能编程语言。您将使用元编程来创建代码,而不是使用诸如SAS之类的宏样式文本替换来创建新功能。 R中的变量名称是符号,而不是字符串。试图迫使这两种不同的编程范例看起来相同,通常不是一个好主意,并且导致两种语言中的一种非常不习惯。

使用R,最好跟踪数据本身而不是数据名称,并跟踪要与符号一起使用的列。

library(tidyverse)

df <- mtcars
var <- rlang::sym("mpg")

那你就可以做

df %>% count(!!var)

或创建一个函数

get_counts <- function(data,x) {
    data %>% count({{x}})
}
get_counts(df,mpg)   #use actual column name
get_counts(df,!!var) #or use name from variable with !!

您可以使用dplyr和:=和一些glue样式的sytnax来命名新变量

df %>% mutate(.,"{var}_1" := !!var/2)

您也可以将其放入函数中

create_new_var <- function(data,x) {
  data %>% mutate(.,"{{x}}_1":={{x}}/2)
}
create_new_var(df,mpg)
create_new_var(df,!!var)

然后,您将只使用管道而不是使用名称中带有数字索引的变量来创建

df %>% 
   create_new_var(!!var) %>%
   length()

或者,如果要使用多个值,则将值保留在命名列表中。然后,您可以在列表上映射功能。对于示例

df_name <- "mtcars"
data <- mget(df_name,inherits = TRUE)
fixed <- map(data,~create_new_var(.,!!var))
lens <- map(fixed,~length(.))
lens$mtcars
# [1] 12
lens[[df_name]]
# [1] 12

如果您在data列表中存储了多个data.frame,这也将起作用

我强烈建议您不要使用这样的东西,但是您可以定义一种新的赋值类型,该赋值类型允许使用字符串变量名。例如

`%<-%` <-  function(x,value) {
  varname <- glue::glue(x,.envir = parent.frame())
  invisible(assign(varname,value,envir = parent.frame()))
}

df_name <- "mtcars"
"{df_name}_1" %<-% { get(df_name) %>% create_new_var(!!var) }

在这里,我们定义了%<-%而不是<-,它将采用类似字符串的名称并将其扩展并将其转换为新变量。然后,我们使用get()获取带有字符串的变量的值。请注意,由于我们无法控制new运算符的优先级,因此需要在要分配给新值的表达式周围加上{}。它的优先级与管道运算符的优先级相同,因此默认情况下,所有内容都会从左到右。这不是适当的R编程可能会做的事情。

,

我看不到需要在R中使用menu2来代替在SA中使用LET的困难。 <ul class="depth1"> <li class="m1"> <router-link to="/introduce/Introduce" @click="selected = 1" :class="{ active: selected == 1 }"><span>menu1</span></router-link> <ul class="depth2 sm1"> <li><router-link to="" @click="selected = 1">sub menu</router-link></li> <li><router-link to="" @click="selected = 1">sub menu</router-link></li> <li><router-link to="" @click="selected = 1">sub menu</router-link></li> </ul> </li> <li class="m2"> <router-link to="/introduce/Introduce" @click="selected = 2" :class="{ active: selected == 2 }"><span>menu2</span></router-link> <ul class="depth2 sm1"> <li><router-link to="" @click="selected = 2">sub menu</router-link></li> <li><router-link to="" @click="selected = 2">sub menu</router-link></li> <li><router-link to="" @click="selected = 2">sub menu</router-link></li> </ul> </li> </ul> <script> export default { data: function () { return { selected: false,}; },methods: { },}; </script> 运算符是将命名字符值转换为R名称或“语言”表达式的机制,get是操作符,因此这似乎是请求的第一部分的精确实现:

dplyr

不过,您接下来的部分将需要使用!!操作。我认为dplyr并没有尝试模仿SAS的宏特性,大多数有经验的R用户都认为这是可憎的。大约10年前,一位R-greats曾努力说明R如何进行宏处理,但我认为他做这件事更多是为了表明为什么不应该这样做,而不是出于任何目的。 R更像SAS。 (我现在要出去寻找文章。)

这里是document.,距20年前已近。转到第11页。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...