问题描述
一年多来,我一直在努力寻找解决方案,并决定为此写一篇文章。任何帮助,将不胜感激。这是我可以在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页。