2

我正在尝试重构一个巨大的数据框(大约 12.000 个案例):在旧数据框中,一个人是一行,大约有 250 列(例如,第 1 个人,测试 A1,测试A2,测试B,...),我想要所有的结果测试 A 的总数(1 - 10 A 的总体和 24 个项目(AY)在一列中,所以一个人最终有 24 列和 10 行。在项目 AY 开始之前还有一个固定的数据框部分(个人年龄、性别等信息),我想保持原样(fixdata)。函数/循环适用于 30 个案例(我提前尝试过),但对于 12.000,它仍在计算,现在将近 24 小时。任何想法为什么?

restructure <- function(data, firstcol, numcol, numsets){
    out <- data.frame(t(rep(0, (firstcol-1)+ numcol)) )
    names(out) <- names(daten[0:(firstcol+numcol-1)])
      for(i in 1:nrow(daten)){
         fixdata <- (daten[i, 1:(firstcol-1)])

          for (j in (seq(firstcol, ((firstcol-1)+ numcol* numsets), by = numcol))){
              flexdata <- daten[i, j:(j+numcol-1)]
              tmp <- cbind(fixdata, flexdata)
              names(tmp) <- names(daten[0:(firstcol+numcol-1)])
              out <- rbind(out,tmp)
          }  
      }
    out <- out[2:nrow(out),]
    return(out)
}

提前致谢!

4

3 回答 3

5

想法为什么:你rbindout在每次迭代中。随着 out 的增长,每次迭代都会花费更长的时间- 因此,随着数据集的增加,您必须期望运行时间的线性增长超过线性增长。

因此,正如 Andrie 所说,您可以查看melt.

或者你可以用核心 R: 来做stack。然后您需要自己将固定部分 cbind 到结果,(您需要重复固定列each = n.var.cols

第三种选择是array2df来自arrayhelpers 包。

于 2011-11-04T12:05:33.147 回答
1

我同意其他人的观点,看看reshape2包装plyr,只是想在另一个方向上添加一点。特别是melt, cast,dcast可能对您有所帮助。另外,使用智能列名可能会有所帮助,例如:

As<-grep("^testA",names(yourdf))
# returns a vector with the column position of all testA1 through 10s.

此外,如果您data.frame在 test# 和 test type 上“花费”了 a 的两个维度,那么该人显然没有任何剩余。当然,您可以通过 ID 识别它们,您可以在绘图时添加美感,但根据您想要做什么,您可能希望将它们存储在list. 因此,您最终会得到一个包含每个人的 data.frame 的人员列表。我不确定您要做什么,但仍然希望这会有所帮助。

于 2011-11-04T17:03:22.197 回答
0

也许您没有获得用于重塑数据组件的 plyr 或其他功能。更直接和低层次的东西怎么样。如果你目前只有一行 A1、A2、A3...A10、B1-B10 等,然后从你的数据框中提取那块东西,我猜是第 11-250 列,然后就做了分割你想要的形状并将它们重新组合在一起。

yDat <- data[, 11:250]
yDF <- lapply( 1:nrow(data), function(i) matrix(yDat[i,], ncol = 24) )
yDF <- do.call(rbind, y) #combine the list of matrices returned above into one
yDF <- data.frame(yDF) #get it back into a data.frame
names(yDF) <- LETTERS[1:24] #might as well name the columns

这是以所需形状获取大量数据的最快方法。该lapply函数所做的只是将维度属性添加到每一行,以便它们具有您想要的形状,然后将它们作为列表返回,并与后续行一起处理。但现在它没有来自主 data.frame 的任何 ID 信息。您只需将前 10 列的每一行复制 10 次。或者您可以使用便利功能merge来帮助解决这个问题。将前 10 行中已有的公共列作为新 data.frame 的列之一,然后将它们合并。

yInfo <- data[, 1:10]
ID <- yInfo$ID
yDF$ID <- rep( yInfo$ID, each = 10 )
newDat <- merge(yInfo, yDF)

现在你已经完成了......大多数情况下,你可能想要创建一个额外的列来命名新行

newDat$condNum <- rep(1:10, nrow(newDat)/10)

这将是非常快速的运行代码。你的 data.frame 真的没有那么大,上面的大部分内容将在几秒钟内执行。

这就是你应该如何看待 R 中的数据。并不是说没有方便的函数来处理大部分数据,而是你应该这样做以尽可能避免循环。从技术上讲,上面发生的事情只有一个循环,一lapply开始就使用。它在那个循环中也很少(当你使用它们时它们应该是紧凑的)。您正在编写标量代码,并且在 R 中它非常非常慢......即使您在执行此操作时并没有真正滥用内存和增长数据。此外,请记住,虽然您不能总是避免某种循环,但您几乎总是可以避免嵌套循环,这是您最大的问题之一。

(阅读内容以更好地了解您在此代码中的问题......您已经在那里犯了大部分大错误)

于 2011-11-04T15:36:49.830 回答