2011-11-04 128 views
2

我正在尝试重构一个巨大的数据框(大约12.000个案例):在旧的数据框中,一个人是一行并且有大约250列(例如Person 1,test A1,testA2, testB,...),并且我想要测试A的所有结果(1到10个A的整体和24个项目(AY)在一列中,所以一个人最终有24列和10行。也是一个固定的数据框部分在项目AY开始之前(像年龄,性别等个人信息),我想保持原样(fixdata) 函数/循环适用于30个案例(我提前试过),但对于12.000,它仍然在计算,现在已经接近24小时了。任何想法为什么?R中的无限函数/循环:数据管理

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

这听起来像是一个重塑问题。看看包'reshape2'中的函数'melt'。你的'data.frame'实际上并不那么庞大。如果'熔化'不能在一秒内处理不了,我会很惊讶。 (类似的问题已经在SO上定期出现了,为了一些灵感,搜索“[r] reshape” – Andrie

+0

Andrie是正确的。一般来说,尽量不要在大数据集上使用for循环,同时你可以尝试如下: 'system.time(restructure([30datasets]))'',然后'system.time(restructure([300datasets]))'等等。这至少会让你知道现有的代码需要多长时间才能完成N个数据集 –

+3

添加一个测试用例将有助于... –

回答

5

想法为什么:你在每次迭代中都会使用rbindout。这将需要更长的每次迭代随着增长 - 所以你必须期望随着数据集的增加运行时间超过线性增长。

所以,正如安德里告诉你可以看看melt

或者您可以使用核心R:stack。 然后,你需要自己cbind固定部分的结果,(你需要each = n.var.cols

第三种方法重复固定列是从包arrayhelpers array2df

+0

融化似乎是有帮助的,但我想知道如何融化数据块的大块。可以说我有ID,TestA1,TestA2,TestB1和TestB2。我想要这样的东西:'行1:ID | TestA1 | TestA2'和'第2行:ID | TestB1 | TestB2'等。融化可能吗? – Elisa

+0

'melt'一路融化数据集,'cast'把它放回你想要的形状。 –

+0

虽然我不能让它融化成块,但它只能逐个融化所有变量......有人知道该怎么做吗? (看上面的例子) – Elisa

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函数都是为每行添加维度属性,以便它们处于所需的形状,然后将它们作为列表返回,并用随后的行进行处理。但是现在它没有来自主数据帧的任何ID信息。你只需要复制前10列的每一行10次。或者,您可以使用便利功能merge来帮助解决该问题。创建一个已经在前10行中的公共列,并将它们合并。

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更好地理解这个代码的问题......你所做的最有大的错误)

1

我与他人同意,考虑reshape2plyr包,只是想在另一个方向添加一点。特别是melt,cast,dcast可能会帮助你。另外,它可能有助于利用智能列名的,例如:

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

此外,如果你对测试#和测试类型“花”一个data.frame的两个维度,有明显没有离开的人。当然,你用一个ID标识它们,你可以在绘图时添加一个美学,但是根据你想要做什么,你可能想要将它们存储在list中。所以你最终得到每个人都有一个data.frame的人员列表。我不确定你想要做什么,但仍然希望这有助于。

+0

也许你也想为我们创建一个最小的例子;) –