【问题标题】:How can I do something like foreach in Stata using R?如何使用 R 在 Stata 中执行类似 foreach 的操作?
【发布时间】:2019-10-14 13:26:43
【问题描述】:

我是 R 新手,正在使用 Stata。我可以在 Stata 中使用 foreach 和 forvalue 遍历变量。

我想遍历列而不是遍历行。例如,我有名为 var1、var2、var3 的列。数据如下:

var1 var2 var3
  1    1   1   
  2   999  3
 999   2  999

我想将变量中的所有“999”值重新编码为缺失值。在Stata,我可以做到

forvalue i = 1(1)3{
  replace var`i' ="NA" if var`i' =="999"
}

因此,我有这样的结果

var1 var2 var3
  1    1   1   
  2   NA   3
  NA   2  NA

另外,如果我有名为 ht、wgt、bmi 的列,我想计算列的平均值并将平均值存储在具有相应名称的新列中。数据集如下:

 ht     wgt   bmi
154.5  43.1 18.1
164.2  63   23.4

在Stata中,我可以做到

foreach i of varlist ht wgt bmi{
  gen `i'mean = mean(`i')
}

结果会是

 ht    wgt   bmi  htmean wgtmean bmimean
154.5  43.1 18.1  159.35  53.05   20.75
164.2  63   23.4  159.35  53.05   20.75

我不知道如何使用 R。

【问题讨论】:

  • 你可能不需要for循环来做R中的任何一个;相应的函数很可能是矢量化的
  • @neilfws 在我看来,Stata 代码在列上循环,因此替换可能类似于 dplyr::mutate_at()
  • 谢谢。是的,@Marius,我想遍历列而不是行。我试过使用mutate_at() 。但是,它给出了评论 Evaluation error: replacement has 0 rows, data has 1492. 我的代码是这样的:f1 <- function(x) dat$x[dat$x==999] <-NA dat <- mutate_at(dat,vars(var1:var21), f1)
  • 如果您放入数据集的小样本(请参阅stackoverflow.com/questions/5963269/…),我们将能够更好地为您提供帮助。
  • @Aaron 谢谢。我在问题中添加了简单的示例。

标签: r loops foreach stata


【解决方案1】:

这里有几个选项。我强烈建议添加一些示例数据,以便我们更好地帮助您。根据您所做的事情,您可以做几件事:

library(dplyr)
mtcars %>% 
    mutate(my_hp = case_when(
        hp<50~"Small",
        hp < 100~"Medium",
        TRUE~"Large"
    ))

这适用于条件逻辑,使用 mutate 函数创建一个新变量(列)和 case_when 函数根据 hp 的值使用不同的情况。

此外,您可以使用看起来像这样的基本 R 方法

mtcars$my_hp <- ifelse(mtcars$hp < 50, "Small",
                                             ifelse(mtcars$hp< 100, "Medium",
                                                         "Large"))

因此,在这种情况下,您将使用检查条件的链式 ifelse 语句创建一个名为 my_hp 的新值。

如果你绝对想做一个循环,在这种情况下你不需要这样做,你可以这样做:

for( i in 1:nrow(mtcars)){
    mtcars$my_hp[i] <- ifelse(mtcars$hp[i] < 50, "Small",
                                                            ifelse(mtcars$hp[i]< 100, "Medium",
                                                                         "Large"))

}

【讨论】:

  • 感谢您的回复。但正如马吕斯所说,我想循环遍历列而不是循环遍历行。我已经编辑了我的问题并给出了一些例子。希望这能让我的问题更清楚。
【解决方案2】:

有很多不同的方法可以做这些事情。例如。对于身高、体重、BMI 示例,您可以使用 for 循环基本上与在 Stata 中相同的方式执行此操作:

# For-loop approach
for (col in c("ht", "wgt", "bmi")) {
    new_col = paste0(col, "_mean")
    df2[, new_col] = mean(df2[, col])
}

不同之处在于代码中的符号和 R 中的字符串之间有更强的分隔,因此您将列名指定为字符串,使用 paste0 创建表示新列名的字符串,然后将它们添加到数据框中。

另一种方法是使用dplyr 包和mutate_at 函数,它将对多个列应用相同的转换:

library(dplyr)

df2 %>%
    mutate_at(c("ht", "wgt", "bmi"), 
              list(mean = ~ mean(.)))

语法有点棘手:首先我们给出列名,然后下一个参数显示我们想要如何转换列。 . 是当前列的占位符,~ 表示 R 不会立即尝试计算 mean(.),而是会等到我们有实际值来替换。当我们使用列表并为转换命名时,如list(transform = ~ . + 2)dplyr 会自动使用名称作为后缀,因此您会得到x_transformy_transform 等列名称。

【讨论】:

  • 非常感谢。两种方法都运作良好。遍历名为 var1、var2、var3 的列怎么样?由于我有 27 列这样命名,我想知道是否有更好的方法来编写代码而不是编写 c("var1", "var2", "var3", "var4",......"var27)
  • 是:paste0("var", 1:27) 将创建列名的完整向量。
【解决方案3】:

一次重新编码多个变量

我想将变量中的所有“999”值重新编码为缺失值。在Stata,我可以做到

forvalue i = 1(1)3{
  replace var`i' ="NA" if var`i' =="999"
}

(为了完整性)您还可以使用lapply 重新编码几个变量。

lapply() 函数接受一组变量并应用一个函数,例如ifelse 给它。您需要使用 [] 子集告诉它数据集和变量,例如data[,variables].
然后你定义你想要做什么,这可能是任何重新编码等你,使用一个变量。 该函数首先在Stata循环中定义类似于“i”本地的东西:function(var),这里var将具有与i类似的作用。 最后,您需要再次使用data[,variables] 说明lapply 的结果去了哪里,即新的或重新编码的变量。

这里是一个例子:

# Example data
data <- data.frame(
  var1 = c( 1,2,999),
  var2 = c(1,999,2),
  var3 = c(1,3,999)
)

# Object with the names of the variables you like to recode.
vars_to_recode <- c("var1","var2","var3")

# Recoding
data[ ,vars_to_recode] <- lapply(data[ ,vars_to_recode],
                                      function(var)
                                        ifelse(var == 999, NA, var)
                                      )
data

#    var1 var2 var3
# 1    1    1    1
# 2    2   NA    3
# 3   NA    2   NA

这实际上更接近于 Stata 的replace,因为原始变量被替换为转换后的变量。

lapply 的替代品是 map(),来自 purrr-package,但特别是对于编程,我(目前)更喜欢基本的 R 函数。

新变量包含旧变量的平均值

也可以使用lapply 回答的问题的第二部分是如何获取包含其他方法的变量。从原始问题:

另外,如果我有名为 ht、wgt、bmi 的列,我想计算列的平均值并将平均值存储在具有相应名称的新列中。 在Stata,我可以做到

foreach i of varlist ht wgt bmi{
  gen `i'mean = mean(`i')
}

解决方案,使用lapply simple 计算平均值并将其放入新变量/列中。这是因为 R 会自动将任何列(“向量”)填充到数据帧的长度(称为“回收”)。

示例数据

df <- data.frame(
      id  = 1:2,
      ht  = c(154.5,164.2),
      wgt = c(43.1 ,63),
      bmi = c(18.1 ,23.4))

定义要更改的变量和新变量的名称。

vars <- names(df[,2:4])

# Names for new variables
newvars <- paste(names(df),"_mean")
newvars
# [1] "ht _mean"  "wgt _mean" "bmi _mean"

生成包含感兴趣变量均值的新变量:

df[,newvars] <- lapply(df[,vars], 
                       function(var)
                           mean(var)
                       )

结果:

df

#   ht  wgt  bmi ht _mean wgt _mean bmi _mean
# 1 154.5 43.1 18.1   159.35     53.05     20.75
# 2 164.2 63.0 23.4   159.35     53.05     20.75

【讨论】:

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