如何有效地合并这些data.tables

时间:2014-11-27 10:21:19

标签: r performance memory data.table

我想创建一个特定的data.table,以便能够检查缺失的数据。 在这种情况下缺少数据并不意味着会有一个NA,但整个行将被省略。所以我需要能够看到一个特定时间依赖列,哪个值缺少哪个级别来自另一列。同样重要的是,如果一起存在大量缺失值,或者它们是否分布在整个数据集中。

所以我有6.000.000x5 data.table(称之为TableA),其中包含时间因变量,级别的ID和我希望添加到最终表的值N.

我有另一个表(TableB),它是207x2。这会将因子的ID与表C中的列耦合。

TableC是1.500.000x207,其中207列中的每一列对应于表B中的ID,行对应于TableA中的时间因变量。

这些表很大,虽然我最近获得了额外的RAM(现在总计达到8GB),但我的计算机不断更换TableC,每次写入都需要回调,之后再次换掉。这种交换是我所有时间的消耗。 TableA每行大约1.6秒,而TableA有6.000.000行,这个操作需要超过100天不间断运行..

目前我正在使用for循环遍历TableA的行。几乎不会立即执行此循环循环操作。我做了一个单行命令,在TableA和TableB中查找TableC的正确列和行号,并将TableA中的值写入TableC。 我打破了这个单线程进行系统时间分析,除了写入大型TableC之外,每个步骤大约需要0秒。 这表明将值写入表是最耗时的并且查看我的内存使用情况我可以看到每当写入发生时会出现一个巨大的块,并且一旦完成它就会消失。

TableA <- data.table("Id"=round(runif(200, 1, 100)), "TimeCounter"=round(runif(200, 1, 50)), "N"=round(rnorm(200, 1, 0.5)))
TableB  <- data.table("Id"=c(1:100),"realID"=c(100:1))
TSM <- matrix(0,ncol=nrow(TableB), nrow=50)
TableC <- as.data.table(TSM)
rm(TSM)
for (row in 1:nrow(TableA))
{
  TableCcol <- TableB[realID==TableA[row,Id],Id]
  TableCrow <- (TableA[row,TimeCounter])
  val <- TableA[row,N]
  TableC[TableCrow,TableCcol] <- val
}

有人可以通过阻止for循环中最后一步的内存交换来告诉我如何更快地完成此操作吗?


编辑:根据@Arun的建议,我花了一些时间来开发一些虚拟数据进行测试。它现在包含在上面给出的代码中。 我没有包含想要的结果,因为虚拟数据是随机的,例程确实有效。它的速度就是问题。

2 个答案:

答案 0 :(得分:0)

不完全确定结果,但是请使用dplyr / tidyr包,因为它们似乎比循环更有效。

install.packages("dplyr")
install.packages("tidyr")
library(dplyr)
library(tidyr)

TableC <- TableC %>% gather(tableC_id, value, 1:207)

这将TableC从1,500,000x207转换为长格式310,500,000x2表格,其中包括&tableff_id&#39; tableC_id&#39;和&#39; tableC_value&#39;列。

TableD <- TableA %>% 
    left_join(TableB, c("LevelID" = "TableB_ID")) %>% 
    left_join(TableC, c("TableB_value" = "TableC_id")

这是我最近一直在使用的一些软件包,它们看起来非常高效,但data.table软件包专门用于管理大型表,因此可能会有很多有用的功能。我还要看看sqldf,它允许您通过SQL命令查询data.frames。

答案 1 :(得分:0)

重新思考我的问题我找到了一个更快的解决方案。 问题是它没有从上面提出的问题出发,因为我已经做了几个步骤来解决我的问题中描述的情况。

输入我聚合TableA的TableX。 TableX包含Id和TimeCounters以及更多,这就是为什么我认为最好创建一个只包含我需要的信息的小表。 TableX还包含相关时间,而在我的问题中,我从一开始就使用完整的时间序列(01-01-1970;))。使用我的TimeCounter列中的级别构建我的TableC会更聪明。

此外,我强迫自己单独设置值,而data.table中的合并速度要快得多。所以我的建议是:每当你需要设置很多值时,尝试找一种合并的方法,而不是单独复制它们。

解决方案:

# Create a table with time on the row dimension by just using the TimeCounters we find in our original data.
TableC <- data.table(TimeCounter=as.numeric(levels(factor(TableX[,TimeCounter]))))
setkey(TableC,TimeCounter) # important to set the correct key for merge.

# Loop over all unique Id's (maybe this can be reworked into something *apply()ish)
for (i in levels(factor(TableX[,Id])))
{
  # Count how much samples we have for Id and TimeCounter
  TableD <- TableX[Id==i,.N,by=TimeCounter]
  setkey(TableD,TimeCounter) # set key for merge
  # Merge with Id on the column dimension
  TableC[TableD,paste("somechars",i,sep=""):=N]
}

TimeCounter中可能缺少步骤,所以现在我必须检查TableC中的间隙并插入所有Id缺失的行。然后我终于可以检查数据差距在哪里以及有多大。