在R中使用do循环来创建新变量

时间:2012-04-20 15:06:25

标签: r sas

我是一名很长时间的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;

谢谢!

6 个答案:

答案 0 :(得分: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,然后不久他们会询问如何为i的某些值访问变量a_i。答案总是将a作为向量或列表。

答案 1 :(得分: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 = ...)))paste(),就可以创建要执行的命令循环。

然后您可以通过以下方式添加您想要执行的操作,即与B_i的求和:

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

然而,其他人是正确的,使用良好的数据结构是一种避免不得不做这样繁琐的事情的方法。然而,当你需要时,这样重复的代码并不难设计。

答案 2 :(得分:6)

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

c_1 = a_1 + b_1

然后abc相关。因此,我建议您将所有变量合并到一个数据框中,其中一列为a,另一列为b

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


根据您的情况,这可能不合适。如果没有,更多信息将是有用的。

答案 3 :(得分: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)]

如果应用于数据框而不是自由变量,我很想知道其他人有什么见解来回答这个问题。

答案 4 :(得分:2)

这已经很晚了,但实际上你可以不用循环或*申请。我假设变量是数据框中的列(如果OP熟悉SAS数据集和宏,这是有意义的。)

df[paste("c", 1:100, sep="_")] <- df[paste("a", 1:100, sep="_")] +
                                  df[paste("b", 1:100, sep="_")]

答案 5 :(得分: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)) 
}

除非你遵循csgillespie的建议(这是正确的方法!),否则我想不出没有eval(parse(yuk))assign的方法。