9

Stata 做得好的一件事是它构造新变量的方式(见下面的例子)。如何在 R 中做到这一点?

foreach i in A B C D {  
    forval n=1990/2000 {  
       local m = 'n'-1  
       # create new columns from existing ones on-the-fly  
       generate pop'i''n' = pop'i''m' * (1 + trend'n')  
   }  
}  
4

4 回答 4

15

不要在 R 中这样做。它混乱的原因是因为它的代码很丑。用程序名称构造大量变量是一件坏事。名字就是名字。它们没有结构,所以不要试图强加给它们。体面的编程语言有这样的结构——垃圾编程语言有附加的“宏”特性,最终会出现这种通过将字符串粘贴在一起来构造变量名的可怕模式。这是 1970 年代的一种做法,现在应该已经消失了。不要成为编程恐龙。

例如,你怎么知道你有多少个 popXXXX 变量?你怎么知道你是否有完整的 pop1990 到 pop2000 序列?如果您想将变量保存到文件中以提供给某人怎么办。呸呸呸。

使用语言为您提供的数据结构。在这种情况下可能是一个列表。

于 2011-02-17T08:05:48.993 回答
9

Spacedman 和 Joshua 都有非常有效的观点。由于 Stata 在任何给定时间在内存中只有一个数据集,我建议将变量添加到数据框(这也是一种列表)而不是全局环境(见下文)。

但老实说,这样做的更多 R-ish 方法是保留您的因子因子而不是变量名称。

我做了一些数据,因为我相信它现在在你的 R 版本中(至少,我希望如此......)

Data <- data.frame(
    popA1989 = 1:10,
    popB1989 = 10:1,
    popC1989 = 11:20,
    popD1989 = 20:11
)

Trend <- replicate(11,runif(10,-0.1,0.1))

然后,您可以使用该stack()函数获取具有因子pop和数值变量的数据框year

newData <- stack(Data)
newData$pop <- substr(newData$ind,4,4)
newData$year <- as.numeric(substr(newData$ind,5,8))
newData$ind <- NULL

填充数据框非常容易:

for(i in 1:11){

  tmp <- newData[newData$year==(1988+i),]
  newData <- rbind(newData,
      data.frame( values = tmp$values*Trend[,i],
                  pop = tmp$pop,
                  year = tmp$year+1
      )
  )
}

在这种格式中,您会发现大多数 R 命令(几年的选择、单个种群的选择、其中一个或两个的建模效果……)以后执行起来要容易得多。

如果你坚持,你仍然可以创建一个宽格式unstack()

unstack(newData,values~paste("pop",pop,year,sep=""))

改编约书亚的答案以将列添加到数据框:

for(L in LETTERS[1:4]) {
  for(i in 1990:2000) {
    new <- paste("pop",L,i,sep="")  # create name for new variable
    old <- get(paste("pop",L,i-1,sep=""),Data)  # get old variable
    trend <- Trend[,i-1989]  # get trend variable
    Data <- within(Data,assign(new, old*(1+trend)))
  }
}
于 2011-02-17T15:39:29.607 回答
3

假设popA1989, popB1989, popC1989,popD1989已经存在于您的全局环境中,下面的代码应该可以工作。当然还有更多“类似 R”的方法可以做到这一点,但我想给你一些类似于你的 Stata 代码的东西。

for(L in LETTERS[1:4]) {
  for(i in 1990:2000) {
    new <- paste("pop",L,i,sep="")  # create name for new variable
    old <- get(paste("pop",L,i-1,sep=""))  # get old variable
    trend <- get(paste("trend",i,sep=""))  # get trend variable
    assign(new, old*(1+trend))
  }
}
于 2011-02-17T03:21:03.450 回答
1

假设您有向量中的人口数据pop1989 和趋势数据trend

require(stringr)# because str_c has better default for sep parameter
dta <- kronecker(pop1989,cumprod(1+trend))
names(dta) <- kronecker(str_c("pop",LETTERS[1:4]),1990:2000,str_c)
于 2011-02-20T07:19:08.990 回答