【问题标题】:R: Appending to a data frame in a for loopR:在for循环中附加到数据帧
【发布时间】:2015-04-05 13:36:12
【问题描述】:

所以我有这个循环,它会写入多个 csv 文件,每个文件都已附加到运行结果之外。正如您在下面看到的那样,这个特定的循环对来自 gex 的子集的每一行针对 mxy 运行一个统计函数 (zScore),然后发布每一行的结果,然后移动到 gex 的下一个子集。

我的问题是,有没有一种方法可以在循环中构建一个看起来相同的数据框,而不是将附加结果写入 csv 文件?

感谢您的热心帮助。

gex <- data.frame("sample" =  c("BIX","HEF","TUR","ZOP","VAG"), 
                  "TCGA-F4-6703-01" = runif(5, -1, 1),
                  "TCGA-DM-A28E-01" = runif(5, -1, 1),
                  "TCGA-AY-6197-01" = runif(5, -1, 1),
                  "TCGA-A6-5657-01" = runif(5, -1, 1))
colnames(gex) <- gsub("[.]", "_",colnames(gex))

listx <- c("TCGA_DM_A28E_01","TCGA_A6_5657_01")

mxy <- data.frame("TCGA-AD-6963-01" = runif(5, -1, 1),
                  "TCGA-AA-3663-11" = runif(5, -1, 1),
                  "TCGA-AD-6901-01" = runif(5, -1, 1),
                  "TCGA-AZ-2511-01" = runif(5, -1, 1),
                  "TCGA-A6-A567-01" = runif(5, -1, 1)) 

colnames(mxy) <- gsub("[.]", "_",colnames(mxy))

zScore <- function(x,y)((as.numeric(x) - as.numeric(rowMeans(y,na.rm=T)))/as.numeric(sd(y,na.rm=T)))

   for(i in seq(nrow(mxy))){
      for(colName in listx){
        zvalues <- zScore(gex[i,colName],
                          mxy[i,])
        geneexptest <- data.frame(gex$sample[i], zvalues, row.names = NULL, 
                                  stringsAsFactors = TRUE)
        write.table(geneexptest, file = paste0(colName, "mxyinput", ".csv"),
                    row.names=FALSE, col.names=FALSE,  quote=F,
                    sep = ",", dec = ".", append=(i > 1))
      }
    }

【问题讨论】:

  • 在循环外声明一个数据框,然后使用rbindcbind在循环的每次迭代中添加行或列?
  • 嘿@SamFirke,感谢您的反馈 - 我如何在仍然利用循环的每次迭代的同时“声明循环外的数据帧”?
  • @SamFirke 这在 R 中通常效率很低——查看 The R Inferno 的第 2 圈。
  • 感谢@josilber 的链接,我知道通常要避免 R 中的 for 循环,但不知道内存影响。 @HenriW,请参阅 josilber 的解决方案;您可以像他一样首先创建一个数据框,然后使用 rbind 调用附加到循环的每次迭代中 - 但正如他所解释的那样,他使用 lapply 的解决方案更好。

标签: r for-loop append


【解决方案1】:

在您发布的代码中,listx 的每个元素都有一个 csv 文件,并且您正在将多行逐行写入每个文件中。相反,您可以为listx 的每个元素创建一个数据框,并通过对write.table 的一次调用将每个元素写出来。

dfs <- lapply(listx, function(colName) {
  do.call(rbind, lapply(seq(nrow(mxy)), function(i) {
    zvalues <- zScore(gex[i,colName], mxy[i,])
    data.frame(gex$sample[i], zvalues, row.names = NULL, stringsAsFactors = TRUE)
  }))
})
dfs
# [[1]]
#   gex.sample.i.    zvalues
# 1           BIX  1.1105593
# 2           HEF  0.5451948
# 3           TUR -1.4060388
# 4           ZOP -1.4218218
# 5           VAG  0.2780513
# 
# [[2]]
#   gex.sample.i.   zvalues
# 1           BIX 2.0607386
# 2           HEF 1.6703912
# 3           TUR 1.3249181
# 4           ZOP 0.8865058
# 5           VAG 1.5289732

现在您可以使用write.table 为每一列输出完整的数据框。

在对rbind 的一次调用中将所有数据帧组合在一起将比在每次循环迭代中调用rbind 更有效;有关详细信息,请参阅 The R Inferno 的第 2 圈。

【讨论】:

  • 我理解你在效率方面的变化,但它并没有按照我想要的方式编译东西。我的问题是,正如您在 OP 中看到的那样,我每次构建它时都会写 geneexptest。关键是write.table 中的append=(i &gt; 1) 选项。我想做同样的事情,但是将geneexptest(以其附加形式......)操作到另一个数据帧中,然后将其写入csv。 (然后进入下一轮,等等)。知道我该怎么做吗?
  • @HenriW 此代码将每个 geneexptest 附加到单个数据帧中。您可以在末尾使用write.table 将其写入文件。不幸的是,您的原始帖子不可复制(我无法运行您发布的代码),因此很难准确复制其功能。如果您需要更多帮助,我会鼓励您更新您的问题以使其可重现。
  • 我附上了一些东西来构建相关的输入 - 请让我知道你的想法。因此,我希望它具有相同的功能,但可以在每轮输出到write.table 之前包含一些额外的操作。这就是为什么我询问在 for 循环中附加数据帧的原因。
  • @HenriW 我已经根据您更新的问题更新了我的代码。这确实突出了在您的 SO 问题中发布可重现的问题示例的重要性。
  • 非常有帮助!!所以,最后一件事:我正在尝试调整循环内的东西,现在显示在原始帖子的补充中。在那里,您可以看到最后一个data.frame(...) 正在尝试生成geneexptotal,而不是像以前那样生成geneexptest。然而,正在生产的实际上是geneexptestapp。有没有理由在那个时候停止?
猜你喜欢
  • 2017-10-21
  • 2016-01-31
  • 2019-02-22
  • 2016-12-19
  • 2021-10-03
  • 1970-01-01
  • 2017-09-29
  • 2017-05-19
  • 2019-10-15
相关资源
最近更新 更多