R中的无限功能/循环:数据管理

时间:2011-11-04 11:07:24

标签: r function for-loop data-management large-data

我正在尝试重组一个庞大的数据框(大约12.000个案例):在旧数据框中,一个人是一行,有大约250列(例如人1,测试A1,testA2,testB,......)我想要测试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)
}

提前致谢!

3 个答案:

答案 0 :(得分:5)

想法原因:您在每次迭代中rbindout。随着数量的增长,这将在每次迭代时花费更长 - 因此,随着数据集的增加,您不得不期望运行时间的线性增长。

所以,正如Andrie所说,你可以看看melt

或者你可以用核心R:stack来做。 然后你需要自己将固定部分与结果联系起来(你需要用each = n.var.cols重复固定的部分

第三种替代方案是来自package arrayhelpers的array2df

答案 1 :(得分:1)

我同意其他人的观点,查看reshape2plyr包,只想在另一个方向添加一点。特别是meltcastdcast可能会对您有所帮助。此外,它可能有助于使用智能列名称,例如:

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

此外,如果您在测试#和测试类型上花费了data.frame的两个维度,那么显然没有人留下。当然,您通过ID识别它们,您可以在绘图时添加美学,但根据您的想法,您可能希望将它们存储在list中。因此,您最终得到的是每个人都有data.frame的人员列表。我不确定你要做什么,但仍然希望这会有所帮助。

答案 2 :(得分: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中非常慢......即使你没有真正滥用内存和增长数据。此外,请记住,虽然你不能总是避免某种循环,但你几乎总能避免嵌套循环,这是你最大的问题之一。

(阅读this以更好地了解您在此代码中的问题...您已经完成了大部分重大错误)