【问题标题】:How to convert foreach in Stata to R?如何将Stata中的foreach转换为R?
【发布时间】:2015-02-10 04:52:09
【问题描述】:

我有一个数据框 (df),其中包含 CA、VT、NC、AZ、CAvalue、VTvalue、NCvalue、AZvalue 等变量。

在 Stata 中,我可以使用foreach 命令和generate 新变量:

foreach x in CA VT NC AZ {
    gen `x'1 = 0
    replace `x'1 = 1 if `x'value > 1
}

当我将此代码转换为 R 时,我发现它有问题。

这是我写的:

x=c("CA","VT","NC","AZ")
x_1=paste(x,"1",sep="")
m1=as.data.frame(matrix(0,ncol=length(x),nrow=NROW(df)))
colnames(m1)=x_1

虽然我在创建以“1”结尾的新变量时没有问题,但我不知道如何转换以“replace”开头的行。我尝试使用 CAtime、VTtime、NCtime 和 AZtime 创建另一个向量。但是我不知道如何在不写四次的情况下将它们合并到循环中。

更新: 最初,我的数据看起来像这样:

df=as.data.frame(matrix(runif(200,1,150),ncol=8,nrow=25))
name=c("CA","VT","NC","AZ","CAtime","VTtime", "NCtime","AZtime")
colnames(df)=name

然后我想在一个新的数据框m1中创建4个新变量CA1、VT1、NC1、AZ1:

x=c("CA","VT","NC","AZ")
x_1=paste(x,"1",sep="")
m1=as.data.frame(matrix(0,ncol=length(x),nrow=NROW(df)))
colnames(m1)=x_1

m1=0中所有变量的值。

然后,如果 CAtime>1,我想要 CA1=1 中的相应单元格。这适用于所有四个变量 CAtime、VTtime、NCtime、AZtime。我不想写四个循环,这就是我被卡住的原因。

【问题讨论】:

  • 倒数第二段的错字:CAvalue、VTvalue、NCvalue、AZvalue,而不是时间。
  • 预期输出是什么
  • 我计划获得 4 个新变量 CA1 VT1 NC1 AZ1。例如,如果 CAvalue>1,则 CA1=1,否则,CA1=0。我的原始数据集有 50 个这样的变量,所以我不能在每个循环中编写 CAvalue>1、VTvalue>1 等 50 个基本循环。
  • 我的代码有错误,=exp required r(100); 但可能是因为我在 linux 上运行它。
  • 但也许这没关系,我会第二次@rawr 并要求您发布您想要的输出,这应该很容易弄清楚。

标签: r stata


【解决方案1】:

df 为例,与您的描述相符:

set.seed(1)
x <- c("CA","VT","NC","AZ")
df <- setNames(data.frame(replicate(8,sample(0:2,5,replace=TRUE),simplify=FALSE)),
      c("CA","VT","NC","AZ","CAvalue","VTvalue","NCvalue","AZvalue"))
df

#  CA VT NC AZ CAvalue VTvalue NCvalue AZvalue
#1  0  2  0  1       2       1       1       2
#2  1  2  0  2       0       0       1       2
#3  1  1  2  2       1       1       1       0
#4  2  1  1  1       0       2       0       2
#5  0  0  2  2       0       1       2       1

现在lapply 检查每列是否有&gt; 1 的值,并将其重新分配给新变量,并在末尾附加1

df[paste0(x,"1")] <- lapply(df[paste0(x,"value")], function(n) as.numeric(n > 1) )
df

#  CA VT NC AZ CAvalue VTvalue NCvalue AZvalue CA1 VT1 NC1 AZ1
#1  0  2  0  1       2       1       1       2   1   0   0   1
#2  1  2  0  2       0       0       1       2   0   0   0   1
#3  1  1  2  2       1       1       1       0   0   0   0   0
#4  2  1  1  1       0       2       0       2   0   1   0   1
#5  0  0  2  2       0       1       2       1   0   0   1   0

【讨论】:

  • 我也可以df[paste0(x,"1")] &lt;- (df[paste0(x, 'value')]&gt;1)+0L
  • @akrun - 当然。我主要是想在与最近从 Stata 过来的人打交道时避免这种诡计。这可能会使事情复杂化,as.numeric 可能是这样做的正式方式。
【解决方案2】:

这是一个可能的选项,使用来自data.tableset,这将是有效的,因为通过引用进行更新。

library(data.table)
setDT(df)[,(x1):= NA]
x2 <- paste0(x, 'value')
indx <- match(x1, names(df))
for(j in seq_along(x2)){
   set(df, i=NULL, j=indx[j], value=as.numeric(df[[x2[j]]]>1))
 }
df
#   CA VT NC AZ CAvalue VTvalue NCvalue AZvalue CA1 VT1 NC1 AZ1
#1:  0  2  0  1       2       1       1       2   1   0   0   1
#2:  1  2  0  2       0       0       1       2   0   0   0   1
#3:  1  1  2  2       1       1       1       0   0   0   0   0
#4:  2  1  1  1       0       2       0       2   0   1   0   1
#5:  0  0  2  2       0       1       2       1   0   0   1   0

更新

假设如果我们需要另一个数据集中的新列,我们可以将结果子集形成一个。或者使用一个修改过的例子,

 setDT(df1)
 setDT(df2)
 x2 <- paste0(x, 'time')
 for(j in seq_along(x2)){
   set(df2, i=NULL, j=j, value=as.numeric(df1[[x2[j]]] >1))
  }

  head(df2,4)
  #  CA1 VT1 NC1 AZ1
  #1:   0   0   1   1
  #2:   0   1   1   0
  #3:   0   0   0   1
  #4:   1   1   0   0

数据

set.seed(1)
x <- c("CA","VT","NC","AZ")
x1 <- paste0(x, 1)

df <- setNames(data.frame(replicate(8,sample(0:2,5,replace=TRUE),
   simplify=FALSE)),c("CA","VT","NC","AZ","CAvalue","VTvalue","NCvalue",
"AZvalue"))

set.seed(425)
df1 <- as.data.frame(matrix(rnorm(200,1,150),ncol=8,nrow=25))
name <- c("CA","VT","NC","AZ","CAtime","VTtime", "NCtime","AZtime")
colnames(df1) <- name

df2 <- as.data.frame(matrix(0,ncol=length(x),nrow=NROW(df1)))
colnames(df2) <- x1

【讨论】:

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