【问题标题】:R nested loop returning only the last iterationR嵌套循环仅返回最后一次迭代
【发布时间】:2014-07-01 17:41:53
【问题描述】:

我正在尝试使用嵌套 for 循环复制实验室存储系统中使用的 81 位低温箱。以下代码说明了使用 3 位框的问题:

urine_random_df <- as.data.frame(c(seq(from = 10, to = 12, by = 1)))
boxcells <- vector()
cell_placeholder <- as.data.frame(c(seq(from = 1, to = 3, by = 1)))
for (i in 1: 3){
        #boxcells <- paste0("NEW", sprintf("%04d", as.numeric(urine_random_df[i,])))
        for (j in 1: nrow(cell_placeholder)){
                boxcells <- c(boxcells, paste(paste0("NEW", sprintf("%04d", as.numeric(urine_random_df[i,]))), cell_placeholder[j,], sep = "-"))        
        }

}


boxcells <- data.frame(boxcells)
names(boxcells) <- "box cells"
boxcells

上面的结果是:

box cells
1 NEW0010-1
2 NEW0010-2
3 NEW0010-3
4 NEW0011-1
5 NEW0011-2
6 NEW0011-3
7 NEW0012-1
8 NEW0012-2
9 NEW0012-3

但是,我想将单元格分组到它们各自的框下,如下所示:

   box cells
1  NEW0010
2  NEW0010-1
3  NEW0010-2
3  NEW0010-3
4  NEW0011
5  NEW0011-1
6  NEW0011-2
7  NEW0011-3
8  NEW0012
9  NEW0012-1
10 NEW0012-2
11 NEW0012-3

我试图通过在外循环中添加boxcells &lt;- paste0("NEW", sprintf("%04d", as.numeric(urine_random_df[i,]))) 来实现这一点。当我用这段代码重新运行代码时,我只得到最后一个框,如下所示:

  box cells
1   NEW0012
2 NEW0012-1
3 NEW0012-2
4 NEW0012-3

似乎循环的每次迭代都会删除最后一个,这样在整个循环完成后,只剩下最后一个框。我发现了一个existing thread here,它建议将“初始化语句”移到循环之外。但是,在这种情况下,初始化语句 urine_random_df...boxcells...cell_placeholder... 已经在循环之外。想法?

【问题讨论】:

  • 为什么要这样的输出?您可以使用此类结果进行进一步处理。您需要将结果放在列表中或包含 2 列( id 、值)的 data.frame 中。
  • @sedeh,你为什么不考虑按照我建议的方式做呢?你为什么要坚持使用 R 中非常低效的嵌套 for 循环?
  • @DavidArenburg 我认为你是对的。您的代码似乎运行良好。我试图了解代码中发生了什么,并可能选择它作为我的答案。

标签: r loops for-loop nested-loops


【解决方案1】:

我认为这里的复杂性来自将循环的输出收集为向量而不是列表。

这里使用列表,然后取消列出并转换为数据框。输出完全符合要求

urine_random_df <- as.data.frame(c(seq(from = 10, to = 12, by = 1)))
boxcells <- list()
cell_placeholder <- as.data.frame(c(seq(from = 1, to = 3, by = 1)))
n <- nrow(cell_placeholder)
for (i in 1:n){
  tmp <- vector()
tmp <- c(paste0("NEW", sprintf("%04d", as.numeric(urine_random_df[i,]))))
      for (j in 1:n){
        tmp <- c(tmp, paste(paste0("NEW", sprintf("%04d", as.numeric(urine_random_df[i,]))), cell_placeholder[j,], sep = "-"))        
      }
      boxcells[[i]] <- tmp 
}


boxcells <- data.frame(unlist(boxcells))
names(boxcells) <- "box cells"
boxcells

这给出了:

 box cells
1    NEW0010
2  NEW0010-1
3  NEW0010-2
4  NEW0010-3
5    NEW0011
6  NEW0011-1
7  NEW0011-2
8  NEW0011-3
9    NEW0012
10 NEW0012-1
11 NEW0012-2
12 NEW0012-3

【讨论】:

  • 也许这回答了这个问题,但你现在应该在 for 循环内做类似 tmp &lt;- c(tmp,..) 的事情在 R 中是非常糟糕的做法(非常慢 + 副作用)
  • 是的,我知道,这是一个非常合理的评论。我只是提出最接近 OP 尝试的方法,并给出他们想要的结果。也许他们会更容易理解,然后从那里继续优化,也许他们有理由限制他们描述的方式。
  • 感谢您的贡献。我想知道是否有办法改进或修改 Ben 的代码以摆脱副作用。
  • 最好全面点赞,选择最佳答案,然后在新问题中寻求优化建议,然后再参考这个问题。
【解决方案2】:

我可以想到在 R 中执行嵌套 for 循环的非常罕见的情况,即使是单个 for 循环也非常罕见。

我会通过做类似的事情来解决这个问题

temp <- expand.grid(sprintf("%04d", as.numeric(urine_random_df[,1])), c("", paste0("-",cell_placeholder[, 1])))
boxcells <- data.frame(box_cells = paste0("NEW", paste0(temp[, 1], temp[, 2])))

哪个会返回

   box_cells
1    NEW0010
2    NEW0011
3    NEW0012
4  NEW0010-1
5  NEW0011-1
6  NEW0012-1
7  NEW0010-2
8  NEW0011-2
9  NEW0012-2
10 NEW0010-3
11 NEW0011-3
12 NEW0012-3

如果您不喜欢该订单,您可以重新订购

boxcells <- data.frame(box_cells = boxcells[order(as.numeric(substr(boxcells$box_cells, 6,7))), ])

   box_cells
1    NEW0010
2  NEW0010-1
3  NEW0010-2
4  NEW0010-3
5    NEW0011
6  NEW0011-1
7  NEW0011-2
8  NEW0011-3
9    NEW0012
10 NEW0012-1
11 NEW0012-2
12 NEW0012-3

【讨论】:

  • dplyrarrange() 也将适用于第一个boxcells 数据框:arrange(boxcells, box_cells)
  • @KaraWoo 差不多但不完全。这是使用 dplyr 进行排序的 sn-p:2211 NEW0036-8 2212 NEW0036-80 2213 NEW0036-81 2214 NEW0036-9。这适用于我更大的数据集。
【解决方案3】:

如果您想更好地对结果进行分组,请选择另一种结构来存储您的结果。这里有两种方法可以简单地解决您的问题:

nn <- paste0('NEW',sprintf("%04d",10:12))

使用列表

setNames(lapply(nn,function(x){
  paste(x,1:3,sep='-')
}),nn)

$NEW0010
[1] "NEW0010-1" "NEW0010-2" "NEW0010-3"

$NEW0011
[1] "NEW0011-1" "NEW0011-2" "NEW0011-3"

$NEW0012
[1] "NEW0012-1" "NEW0012-2" "NEW0012-3"

使用data.frame

transform(expand.grid(nn,1:3),Var2=paste(Var1,Var2,sep='-'))

     Var1      Var2
1 NEW0010 NEW0010-1
2 NEW0011 NEW0011-1
3 NEW0012 NEW0012-1
4 NEW0010 NEW0010-2
5 NEW0011 NEW0011-2
6 NEW0012 NEW0012-2
7 NEW0010 NEW0010-3
8 NEW0011 NEW0011-3
9 NEW0012 NEW0012-3

【讨论】:

  • 这可能是问题的解决方案,但不是问题的答案 :) 好吧,让我们看看 OP 认为什么更重要(以及你的读心能力有多好! )
  • @Ben 我不是来提供解决方案(无意冒犯),而是展示解决问题的最佳 R 方法。
  • @agstudy 你的建议很有创意。但是,我需要在输出中使用严格的格式。我认为 Ben 和我的思路是一样的,尽管我现在需要担心 tmp &lt;- c(tmp,..) 的缓慢性。无论如何要绕过tmp &lt;- c(tmp,..)
猜你喜欢
  • 2020-06-30
  • 1970-01-01
  • 2016-05-10
  • 1970-01-01
  • 2014-06-18
  • 2019-12-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多