R:使用 data.table 进行制表和插入

标签 r sparse-matrix data.table

我正在尝试获取具有多个索引的非常大的一组记录,计算由索引子集确定的组的汇总统计数据,然后将其插入表中的每一行。这里的问题是这些是非常大的表——每个表超过 1000 万行。

再现数据的代码如下。

基本思想是有一组索引,比如 ix1, ix2, ix3, ..., ixK。通常,我只选择其中的几个,比如 ix1 和 ix2。然后,对于名为 val 的列,我计算具有匹配 ix1 和 ix2 值的所有行的聚合(针对出现的所有组合)。 .为简单起见,我将重点放在总和上。

我尝试了以下方法

  • 通过稀疏矩阵:将值转换为坐标列表,即 (ix1, ix2, val),然后创建一个 sparseMatrix - 这很好地总结了所有内容,然后我只需要从稀疏矩阵表示转换回坐标列表。速度:很好,但它做的比必要的多,并且不能推广到更高的维度(例如 ix1、ix2、ix3)或比总和更通用的函数。
  • 使用 lapplysplit :通过创建一个对所有 (ix1, ix2, ...) n 元组都是唯一的新索引,我可以使用 split 和 apply。这里不好的是,唯一索引是由 split 转换的。成一个因素,而这种转换非常耗时。试试 system({zz <- as.factor(1:10^7)}) .
  • 我现在正在尝试 data.table , 通过类似 sumDT <- DT[,sum(val),by = c("ix1","ix2")] 的命令.但是,我还不知道如何合并 sumDTDT , 除了通过类似 DT2 <- merge(DT, sumDT, by = c("ix1","ix2"))

  • 是否有比通过 merge 更快地连接 data.table 的方法?我描述的操作?

    【我也试过bigsplit来自 bigtabulate包,以及其他一些方法。任何转换为​​因子的东西都差不多 - 据我所知,转换过程非常缓慢。]

    生成数据的代码。当然,最好尝试更小的N看到某些东西有效,但并非所有方法都适用于 N >> 1000。
    N   <-  10^7
    set.seed(2011)
    ix1 <-  1 + floor(rexp(N, 0.01))
    ix2 <-  1 + floor(rexp(N, 0.01))
    ix3 <-  1 + floor(rexp(N, 0.01))
    val <-  runif(N)
    
    DF  <-  data.frame(ix1 = ix1, ix2 = ix2, ix3 = ix3, val = val)
    DF  <- DF[order(DF[,1],DF[,2],DF[,3]),]
    DT  <- as.data.table(DF)
    

    最佳答案

    好吧,您可能会发现,只要您的 key 进行合并并没有那么糟糕。 s 设置正确。

    让我们再次设置问题:

    N   <-  10^6      ## not 10^7 because RAM is tight right now
    set.seed(2011)
    ix1 <-  1 + floor(rexp(N, 0.01))
    ix2 <-  1 + floor(rexp(N, 0.01))
    ix3 <-  1 + floor(rexp(N, 0.01))
    val <-  runif(N)
    DT <- data.table(ix1=ix1, ix2=ix2, ix3=ix3, val=val, key=c("ix1", "ix2"))
    

    现在您可以计算您的汇总统计数据
    info <- DT[, list(summary=sum(val)), by=key(DT)]
    

    并以“data.table 方式”合并列,或仅与 merge 合并
    m1 <- DT[info]            ## the data.table way
    m2 <- merge(DT, info)     ## if you're just used to merge
    identical(m1, m2)
    [1] TRUE
    

    如果这些合并方式中的任何一种都太慢,您可以尝试一种棘手的方式来构建 info以内存为代价:
    info2 <- DT[, list(summary=rep(sum(val), length(val))), by=key(DT)]
    m3 <- transform(DT, summary=info2$summary)
    identical(m1, m3)
    [1] TRUE
    

    现在让我们看看时间:
    #######################################################################
    ## Using data.table[ ... ] or merge
    system.time(info <- DT[, list(summary=sum(val)), by=key(DT)])
       user  system elapsed 
      0.203   0.024   0.232
    
    system.time(DT[info])
       user  system elapsed 
      0.217   0.078   0.296
    
    system.time(merge(DT, info))
       user  system elapsed 
      0.981   0.202   1.185
    
    ########################################################################
    ## Now the two parts of the last version done separately:
    system.time(info2 <- DT[, list(summary=rep(sum(val), length(val))), by=key(DT)])
       user  system elapsed 
      0.574   0.040   0.616 
    
    system.time(transform(DT, summary=info2$summary))
       user  system elapsed 
      0.173   0.093   0.267
    

    或者你可以跳过中间 info如果以下内容对您的口味来说似乎不太高深,则可以构建表格:
    system.time(m5 <- DT[ DT[, list(summary=sum(val)), by=key(DT)] ])
       user  system elapsed 
      0.424   0.101   0.525 
    
    identical(m5, m1)
    # [1] TRUE
    

    关于R:使用 data.table 进行制表和插入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7367965/

    相关文章:

    java - 在 Java 中表示上三角矩阵的最佳数据结构是什么?

    python - 获取稀疏矩阵的存储元素数量 - Python

    在 R 中的数据表中按降序重新标记簇(列)

    r - 使用 data.table 查找时间戳对之间重叠的持续时间

    r - R strucchange中断点时间序列模型的模型比较

    r - ggplot2 中 glm 和 stat_smooth 的逻辑回归预测值不同

    python - 使用Python进行大型交易数据集的市场购物篮分析

    R data.table 条件在组内,但在组中的第一个实例中记录

    R:ggplot 设置带有自定义中断的 ylim

    r - 为什么这行得通?创建与基函数同名的逻辑函数仍然允许使用该函数