【问题标题】:How to efficiently merge these data.tables如何有效地合并这些 data.tables
【发布时间】:2014-11-27 10:21:19
【问题描述】:

我想创建一个特定的 data.table 来检查丢失的数据。 在这种情况下,缺少数据并不意味着会有 NA,而是整行都会被遗漏。因此,我需要能够查看某个与时间相关的列,而另一列的哪个级别缺少哪些值。同样重要的是是否存在大量缺失值,或者它们是否分布在数据集中。

所以我有这个 6.000.000x5 的 data.table(称之为 TableA),其中包含时间相关变量、级别的 ID 和我想添加到最终表格中的值 N。

我有另一个 207x2 的表 (TableB)。这会将因子的 ID 耦合到 TableC 中的列。

TableC 为 1.500.000x207,其中 207 列中的每一列对应 TableB 中的 ID,行对应 TableA 中的时间相关变量。

这些表很大,虽然我最近获得了额外的 RAM(现在总计 8GB),但我的计算机一直在交换 TableC,每次写入都必须回调它,然后再被交换掉。这种交换是我所有时间的消耗。 TableA 的每行大约需要 1.6 秒,并且由于 TableA 有 6.000.000 行,因此此操作将需要超过 100 天的不间断运行..

目前我正在使用 for 循环来循环 TableA 的行。不做任何操作,这个 for 循环几乎立即循环。我做了一个单行命令,在 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 的建议,我花了一些时间开发一些虚拟数据进行测试。它现在包含在上面给出的代码中。 我没有包括想要的结果,因为虚拟数据是随机的,并且例程确实有效。问题在于速度。

【问题讨论】:

  • 请提供您的问题的最小可重现示例,以及您需要的解决方案。 ATM 后面的文字太多了。
  • 我可以提供一些代码,但没有数据。另外,如何生成可重现的内存问题示例?
  • 让我想想.. 你可以提供代码来生成你的表的小数据集。然后告诉我们你的代码是什么。然后向我们展示该代码的结果。然后解释这不会扩展到您的数据维度。然后询问如何解决内存问题。另外,您说内存问题,并以“如何使此操作更快?”结束您的帖子。
  • 也许你应该阅读我的问题的其余部分 :) 缓慢是因为内存交换问题。
  • 你是对的。我会让别人接手。祝你好运。

标签: r performance memory data.table


【解决方案1】:

不完全确定结果,但可以试试 dplyr/tidyr 包 for,因为它们似乎比 for 循环更节省内存。

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

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

这会将 TableC 从 1,500,000x207 转换为具有“tableC_id”和“tableC_value”列的长格式 310,500,000x2 表。

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

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

【讨论】:

    【解决方案2】:

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

    输入我从中聚合 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 都缺少的行。然后我终于可以检查我的数据差距在哪里以及有多大。

    【讨论】:

      猜你喜欢
      • 2019-09-24
      • 2017-07-31
      • 1970-01-01
      • 2014-08-17
      • 2013-03-06
      • 2012-10-27
      • 1970-01-01
      • 2010-11-03
      • 2011-11-08
      相关资源
      最近更新 更多