我正在尝试重组一个庞大的数据框(大约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)
}
提前致谢!
答案 0 :(得分:5)
想法原因:您在每次迭代中rbind
到out
。随着数量的增长,这将在每次迭代时花费更长 - 因此,随着数据集的增加,您不得不期望运行时间的线性增长。
所以,正如Andrie所说,你可以看看melt
。
或者你可以用核心R:stack
来做。
然后你需要自己将固定部分与结果联系起来(你需要用each = n.var.cols
重复固定的部分
第三种替代方案是来自package arrayhelpers的array2df
。
答案 1 :(得分: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
的两个维度,那么显然没有人留下。当然,您通过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以更好地了解您在此代码中的问题...您已经完成了大部分重大错误)