【问题标题】:How to rewrite this Stata code in R?如何在 R 中重写这个 Stata 代码?
【发布时间】:2011-06-28 19:23:57
【问题描述】:

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')  
   }  
}  

【问题讨论】:

  • 对于那些不会说stata的人,也许添加最终输出应该是什么样子?以及与此相关的输入数据......
  • 我想知道统计软件包的哪个白痴设计者认为 1990/2000 是一个范围而不是一个部门facepalm
  • @Spacedman:你不知道它的一半。我用了 3 年的 Stata。最糟糕的。编程。语言。永远。
  • @Joshua : 请允许我同意 :-) 但不得不说,它是一个相当强大的统计软件包。除了编写分析脚本之外,您不应该梦想其他任何事情。
  • @Joris:虽然我没有明确表示,但我同意 Stata 有很多的统计能力。这就是为什么我特别小心地说在Stata 中的编程 很糟糕。 ;-)

标签: r stata


【解决方案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)

【讨论】:

    【解决方案2】:

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

    但老实说,这样做更 R 的方式是保留您的因数,而不是变量名。

    我制作了一些数据,因为我相信它现在在您的 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)))
      }
    }
    

    【讨论】:

    • 你能解释一下“保留你的因子而不是变量名”是什么意思吗?
    • @KevinM 这就是“长格式”和“宽格式”之间的区别。您将所有数据放在一个列中,并使用一个因子或分类变量来描述哪些数据来自哪个人口和年份。如果您使用变量名称来指示我们正在谈论的年份和人口,那么您将难以使用该信息。就统计分析而言,人口和年份都是分类变量。所以我把它们作为一个分类变量(因子),而不是把它们组合起来构造变量名。
    【解决方案3】:

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

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

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

    【讨论】:

      【解决方案4】:

      假设您的全局环境中已经存在popA1989popB1989popC1989popD1989,下面的代码应该可以工作。当然还有更多“类似 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))
        }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-06-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多