【问题标题】:In R, how do I use stub to create names (of data frames, variables & plots) in a loop?在 R 中,如何使用存根在循环中创建(数据框、变量和图的)名称?
【发布时间】:2015-08-19 12:18:55
【问题描述】:

我正在使用 R 中 INLA 包的一组结果。这些结果存储在具有有意义名称的对象中,因此我可以在当前环境中拥有例如 model_amodel_b... .对于这些模型中的每一个,我都想做几个处理任务,包括将数据提取到单独的数据框,然后可以将其用于合并到空间数据以创建地图等。

转向更简单、可重现的示例,让我们假设两个结果

ctl <- c(4.17,5.58,5.18,6.11,4.50,4.61,5.17,4.53,5.33,5.14)
trt <- c(4.81,4.17,4.41,3.59,5.87,3.83,6.03,4.89,4.32,4.69)
group <- gl(2, 10, 20, labels = c("Ctl","Trt"))
weight <- c(ctl, trt)
model_a <- lm(weight ~ group)
model_b <- lm(weight ~ group - 1) 

我可以处理单个模型的步骤,例如:

model_a_sum <- data.frame(var = character(1), model_a_value = numeric(1))
model_a_sum$var <- "Intercept"
model_a_sum$model_a_value <- model_a$coefficients[1]

png("model_a_plot.png")
plot(model_a, las = 1)
dev.off()

现在,我想为每个模型重用这段代码,本质上是根据我使用的模型构建正确的名称。我比 R 人更 Stata,并且在 Stata 内部,使用名称的存根(model_a,甚至仅a..)并构建将实现所有步骤的foreach 循环将是一项微不足道的任务,为每个模型调整名称。

在 R 中,for 循环在整个互联网上都受到抨击,所以我认为我不应该尝试涉足以下领域:

models <- c("model_a", "model_b", "model_c")

for (model in models) {

  ...

}

对于这种情况,更好的解决方案是什么?


更新 1:由于 cmets 建议 for 可能确实是一个选项,我试图将所有任务放入一个循环中。到目前为止,我设法使用assign 正确命名数据框,并使用get 以正确的名称绘制正确的数据:

models <- c("model_a", "model_b")

for (i in 1:length(models)) {

  # create df
  name.df <- paste0(models[i], "_sum")
  assign(name.df, data.frame(var = character(1), value = numeric(1)))

  # replace variables of df with results from the model

  # plot and save
  name.plot <- paste0(models[i], "_plot.png")
  png(name.plot)
  plot(get(models[i]), which = 1, las = 1)
  dev.off()  

}

这是合理的方法吗?有更好的解决方案吗?

我无法解决的一件事是根据模型命名 df 的第二个变量(即model_a_value 而不是当前的value。任何想法如何解决这个问题?

【问题讨论】:

  • 我认为for 解决方案在这种情况下是一个不错的选择,您的函数将像您一样生成要写入磁盘的文件。使用对象名称作为变量,然后 for (i in 1:length(models)) your.function(models[i]) 为您的流程创建一个函数。
  • 我认为 for 循环完全适合这种任务,但如果你有大量的模型对象要处理,你可能会从并行化中受益——在这种情况下,我会使用foreach 包。
  • "在 R 中,for 循环在整个互联网上都受到了抨击 " 互联网上的一切都永远存在,R 中的 for 循环 很慢,现在已经不是这样了,所以没有有理由在选择它们时避免使用它们。如果您可以使用“矢量化”(即仅使用可以将矢量作为入口的函数)方式,请避免使用它们,因为处理已针对此进行了优化。
  • 另一种选择是列出您的模型公式;然后制作单独的函数a)估计模型并提取系数和b)估计然后绘制模型;然后分别使用lapply()rapply() 将这些函数应用于模型公式列表。
  • @hoffmanc @Tensibai @ulfelder 感谢所有 cmets。将尝试追求for 解决方案。

标签: r for-loop


【解决方案1】:

一些一般提示/建议:

  1. 正如 cmets 中所提到的,不要相信 R 中的 for 循环的负面影响。问题不在于它们不好,而更多的是它们与一些效率低下的不良代码模式相关.

  2. 更重要的是使用正确的数据组织。 不要将模型分别放在单独的对象中!。将它们放在一个列表中:

    l <- vector("list",3)
    l[[1]] <- lm(...)
    l[[2]] <- lm(...)
    l[[3]] <- lm(...)
    
  3. 然后给列表命名:

    names(l) <- paste0("model_",letters[1:3])
    

现在您可以循环遍历列表,而无需使用笨拙且不必要的工具,例如 assignget,更重要的是,当您准备好从 for 循环升级到像 lapply 这样的工具时一切顺利。

我也会对您的数据框使用类似的策略。

【讨论】:

  • 即使我回答了最初的问题,因为有时您无法选择输入的内容,我完全同意这篇文章。
  • 谢谢@joran。将尝试调整代码以使用所有模型的列表。但是有一个问题:该解决方案是否意味着我必须指定将在此处使用的模式数量?在你的情况下 - 3?
  • @radek 是的。从技术上讲,可以简单地分配到列表的末尾并扩大它,但这将很难扩展,因为它会强制进行大量复制。可以创建一个高估最终长度的列表,然后删除不需要的条目。
  • 我没有“从 for 循环移动到 lapply”的兴趣,for (m in models) {lapply(models,function(x) { 在功能上是等效的, lapply 甚至会慢一点。我在那里忘记了什么? (因为我很确定我确实忘记了一些东西:))
【解决方案2】:

查看@joran 的答案,这是为了展示assignget 的使用,但应尽可能避免。

我会在 for 循环中使用这种方式:

for (model in models) {
  m <- get(model) # to get the real model object
  # create the model_?_sum dataframe
  assign(paste0(model,"_sum"), data.frame(var = "Intercept", value = m$coefficients[1]))
  assign(paste0(model,"_sum"), setNames( get(paste0(model,"_sum")), c("var",paste0(model,"_value"))) ) # per comment to rename the value column thanks to @Franck in chat for the guidance

  # paste0 to create the text
  png(paste0(model,"_plot.png"))
  plot(m, las = 1) # use the m object to graph
  dev.off()
}

给出两个图像和这个:

> model_a_sum
                var value
(Intercept) Integer 5.032
> model_b_sum
             var value
groupCtl Integer 5.032
> 

我不确定您为什么希望使用此数据框,但我希望这可以提供有关如何创建变量名称以及如何访问它们的线索。

【讨论】:

  • 谢谢。一个问题:是否可以动态替换value 以反映它来自的模型?例如将其命名为model_a_value。至于拥有这个数据框的原因 - 我正在使用 INLA 对象并从那里获得结果,这些结果用于进一步处理以获取我使用的区域(边际、概率)的特定区域(这是空间模型)值地图和图表,以及我用来为 LaTeX 构建一个汇总多个模型的表格的汇总度量。
  • @radek 更新了答案,在聊天室得到了@Franck 的帮助
  • 非常感谢!虽然不推荐(分配和获取...),但这个解决方案让我最接近我想要实现的目标。
  • @radek 请问您是如何获得现实中的变量的?也许在使用它们之前从它们构建一个列表可能是一种正确的方法(一个初始循环来构建一个列表/数据框,您可以在不使用分配/获取的情况下填充以继续工作)
  • @radek 如果我理解正确的话,具有有意义的列名称和有意义的行名称的数据框可能是正确的表示,而不是分隔的变量。但也许我们正在远离这个问题,我会尝试花一些时间来更新答案,举例说明我的意思是使用这个问题数据(模型和模型和)(旁注,我不是统计学家,所以我不知道大多数用例)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-08-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多