2

我是一名长期的 SAS 程序员,希望跳转到 R。我知道 R 对于变量重新编码并不是那么好,但是有没有办法通过 do 循环来做到这一点。

如果我有很多名为 a_1 a_2...a_100、b_1 b_2 ... b_100 的变量,并且我想创建新变量 c_1 c_2 ... c_100,其中 c_i = a_i + b_i。有没有办法在没有 100 条语句的情况下做到这一点?

在 SAS 中,我会简单地使用:

%do i=1 %to 100;
c_&i = a_&i + b_&i;
%end;

谢谢!

4

6 回答 6

22

SAS 使用一种基本的宏语言,它依赖于文本替换,而不是像任何适当的编程语言那样评估表达式。您的 SAS 文件本质上是两件事:SAS 命令和宏表达式(以 '%' 开头的东西)。宏语言存在很大问题且难以调试(例如,表达式中的表达式是否会扩展?为什么必须使用“&&x”甚至“&&&x”?为什么这里需要两个分号?)。与基于单一语法的精心设计的编程语言相比,它笨拙且不优雅。

如果您的 a_i 变量是单个数字,那么您应该将它们作为向量 - 例如:

> a = 1:100
> b = runif(100)

现在我可以轻松获取元素:

> a[1]

并并行加起来:

> c = a + b

你可以用一个循环来做,首先初始化 c :

> c = rep(0,100)
> for(i in 1:100){
   c[i]=a[i]+b[i]
   }

但这会很慢。

几乎每个 R 初学者都会问“我如何为 i 的某些值创建变量 a_i”,然后不久他们又问如何访问变量 a_i 以获得 i 的某些值。答案总是将 a 作为向量或列表。

于 2012-04-20T15:52:58.920 回答
7

这东西很琐碎。对我来说,您似乎想找到一种自动创建命令并执行它们的方法。十分简单。

例如,这分配给 中C_i的值A_i

for(i in 1:100){
    tmpCmd = paste("C_",i,"= A_",i, sep = "")
    eval(parse(text = tmpCmd))
}
rm(i, tmpCmd)

只要记住eval(parse(text = ...)))and paste(),您就可以开始创建要执行的命令循环了。

然后,您可以通过在此行中交换来添加您想要执行的操作,即用 求和B_i

    tmpCmd = paste("C_",i,"= A_",i," + B_",i, sep = "")

然而,其他人是对的,使用好的数据结构是一种避免做很多像这样乏味的事情的方法。然而,当您需要时,这样的重复代码并不难设计。

于 2012-04-21T12:05:54.960 回答
6

我怀疑如果你有一百个变量a_1, a_2, ..., a_100,那么你所有的变量都是相关的。事实上,如果你想做

c_1 = a_1 + b_1

那么a, b,c是相关的。因此,我建议您将所有变量组合到一个数据框中,其中一列是a,另一列是b

问题是如何以合理的方式组合变量。但是,为了给出一个有用的答案,您能告诉我们这些变量是如何创建的吗?


也许这不适合您的情况。如果没有,更多信息会很有用。

于 2012-04-20T15:07:47.713 回答
2

这真的很晚了,但实际上你可以在没有循环或 *apply 的情况下做到这一点。我假设变量是数据框中的列(如果 OP 熟悉 SAS 数据集和宏,这是有道理的)。

df[paste("c", 1:100, sep="_")] <- df[paste("a", 1:100, sep="_")] +
                                  df[paste("b", 1:100, sep="_")]
于 2013-08-19T07:30:46.837 回答
2

这实际上是一个非常有趣的问题。从我的阅读和最近(强制)使用 SAS 来看,问题似乎是试图在一个data步骤中使用一些宏代码重新编码 SAS 数据集中的变量。否则,如果它们是创建的自由变量,它们将以&字符开头。我认为示例代码实际上会更好地表示为:

%macro recodevars;
data test;
  set test;

  %do i=1 %to 100;
  c_&i = a_&i + b_&i;
  %end;

run;
%mend recodevars;
%recodevars;

你可以像这个例子一样在 R 中做类似的事情:

test <- data.frame(vara1=1:10,varb1=2:11,vara2=3:12,varb2=4:13)

test[paste0("varc",1:2)] <- test[paste0("vara",1:2)] + test[paste0("varb",1:2)]

如果将其应用于数据框而不是自由变量,我很想知道其他人必须回答什么见解。

于 2012-04-22T23:42:53.110 回答
1

R方式是使用列表。

> a_1 = 1
> a_2 = 2
> a_3 = 3
> a_4 = 4
> a_5 = 5

> b_1 = 1
> b_2 = 2
> b_3 = 3
> b_4 = 4
> b_5 = 5

> a.list <- ls(patter='a_*')
> a.list
[1] "a_1" "a_2" "a_3" "a_4" "a_5"

并定义 blist 。

if(length(a.list)==length(b.list)){
   c.list <- lapply(1:length(a.list), function(x) eval(parse(text=a.list[x])) + eval(parse(text=b.list[x])))

   c.list.names <- paste('c', 1:length(a.list), sep='_')

   lapply(1:length(c.list), function(x) assign(c.list.names[x], c.list[x], envir=.GlobalEnv)) 
}

除非您遵循csgillespieeval(parse(yuk))assign建议(这是正确的方法!)

于 2012-04-20T15:21:03.933 回答