【问题标题】:understanding R performance plyr - dply and Factor variables了解 R 性能 plyr - dply 和因子变量
【发布时间】:2016-10-04 17:39:30
【问题描述】:

我的电脑是 Intel Core i7、12GB RAM 和 Windows 10,只是为了给你一些背景信息。我正在尝试对数据帧执行一个简单的操作,该数据帧大约有 41K entries 并且它在.csv 格式中的大小约为 20MB。 数据框有 4 列:

  1. 地址:因子变量,具有大约 41K 个不同级别(无重复级别)
  2. Block:Factor 变量,具有大约 39K 个不同的级别(大多数 Block 只有一个与其相关的地址,但其他最多有 100 个
  3. 能量:一个 int 变量
  4. 细分:因子变量,只有 7 个级别

让我给你看一下dataFrame的summary()输出:

         Address            Block           ENERGY        Segment     
 BAC0602532301:    1   A33093097:  165   Min.   :      0   A   :11863  
 BAC0603557493:    1   B79083796:  165   1st Qu.:  48590   A+  : 7723  
 BAC0604416292:    1   A08721177:  158   Median :  75420   A++ : 3948  
 BAE0602962660:    1   A46581666:  153   Mean   : 144694   A+++: 2324  
 BAE0603336589:    1   B21053848:  138   3rd Qu.: 154167   B   : 8110  
 BAI0602739803:    1   A08119687:   89   Max.   :2802501   C   : 4051  
 (Other)      :40086   (Other)  :39224                     D   : 2073   

现在,我要执行的操作是对于每个 Block(大约有 39K)选择 ENERGY 列的最大值地址 和 Segment 与此 ENERGY 相关。

所以要做到这一点,我知道有很多不同的选择。我通常尝试使用 plyrdplyr 包中的函数,因为我认为它们比 Basic 包的其他选项更快,特别是如果操作可以被认为是 Split-Appy-Combine 操作。 问题是,如果我从 plyr 包中执行此操作:

 ddply(dataFrame, "Block", summarize, AddressMax =  Address[which.max(ENERGY)], SegmentMax = Segment[which.max(ENERGY)], EnergyMax = max(ENERGY))

计算机永远不会结束,我最终不得不杀死 R 程序

如果我从 dply 包中执行此操作:

Blocks <- group_by(DataFrame,Blocks)

MaxsbyBlock <- summarise(Blocks, AdressMax = Address[which.max(ENERGY)], SegmentMax = Segment[which.max(ENERGY)], EnergyMax = max(ENERGY))

完成大约需要 30 到 40 秒(至少完成!!!)。

否则,如果我放弃尝试使用 ddply 恢复地址,它会完美运行,事实上,如果您执行此操作(请注意,现在 AdressMax 已消失):

ddply(dataFrame, "Block", summarize,SegmentMax = Segment[which.max(ENERGY)], EnergyMax = max(ENERGY))

大约需要 3 到 4 秒才能完成。ddply 策略改进得更多。那么,有人可以告诉我,尝试使用 ddply 或 dply 包恢复 Adress Factor 变量的值有什么问题吗?如果您使用 __aggregate 函数并 merge 它会更快,我想至少了解一点原因:

aggdata<-aggregate(Energy~Blocks, data=dataFrame, max)
merge(aggdata,dataFrame,by.x=c('Blocks','Energy'),by.y=c('Blocks','Energy'))

【问题讨论】:

    标签: r plyr


    【解决方案1】:

    我注意到这个问题已经有 5 天没有得到回答或评论了。

    我无法解释为什么 plyrdplyr 方法没有按预期执行,但如果 OP 有兴趣解决根本问题,这里有两种使用 data.table 的方法。

    对三种方法进行基准测试

    使用下面创建的虚拟数据DT,正在对三种不同的方法进行基准测试:

    • base_agg_merge:使用 Q 中给出的基函数进行聚合和合并
    • dt_agg_merge:使用data.table 聚合和加入
    • dt_order_group:使用data.table 进行排序和分组

    Q 中的其他方法需要太多的运行时间(dplyr:22 秒,plyr 没有 AddressMax:2.6 秒),因此它们在 microbenchmark 运行中被省略了。

    library(microbenchmark)
    library(data.table)
    microbenchmark(
      base_agg_merge = {
        aggdata <- aggregate(Energy ~ Block, data = DT, max)
        result1 <- merge(aggdata, DT, by = c("Block", "Energy"))
      },
      dt_agg_merge = {
        temp <- DT[, .(max_Energy = max(Energy)), keyby = Block]
        result2 <- DT[temp, on = c("Block", Energy = "max_Energy")]
      },
      dt_order_group = {
        result3 <- DT[order(-Energy), .SD[1], keyby = Block]
      },
      times = 10
    )
    
    Unit: milliseconds
               expr        min         lq       mean     median         uq        max neval
     base_agg_merge 275.106516 279.646932 297.287758 281.229186 302.062803 395.936697    10
       dt_agg_merge   7.527084   7.789126   9.489412   9.001351   9.342873  17.171266    10
     dt_order_group   4.458858   5.437927   6.508181   6.784382   7.405881   8.685504    10
    

    最快的方法dt_order_group工作如下:

    • Energy 订购(反向)
    • 分组Block
    • 返回每组的第一行

    虽然base_agg_mergedt_agg_merge遵循相同的思路,但data.table版本快30倍:

    • 分组Block
    • 为每个组获取max(Energy)
    • 合并Blockmax_Energy(注意,这应该返回任何关系,即组中具有相同max_Energy 的行)

    基准测试在配备 Intel Core i5、8 GB RAM、使用 R 版本 3.3.1 和 data.table 的开发版本 1.9.7 的 Windows 10 的 PC 上运行(请参阅 Installation instructions

    数据

    OP 提供了基础数据的summary(),这对模拟虚拟数据非常有帮助。

    set.seed(1234)
    n <- 41000L
    m <- 10000L
    dataFrame <- data.frame(
      Address = factor(m + sample.int(n)),
      Block = factor(m + sample.int(39000L, n, replace = TRUE, prob = 1/seq_len(39000L))),
      Energy = as.integer(rlnorm(n, meanlog = 11)),
      Segment = factor(sample(LETTERS[1:7], n, replace = TRUE))
    )
    summary(dataFrame)
    ##     Address          Block           Energy        Segment 
    ##  10001  :    1   10001  : 3714   Min.   :   1294   A:5871  
    ##  10002  :    1   10002  : 1849   1st Qu.:  30579   B:5762  
    ##  10003  :    1   10003  : 1247   Median :  59730   C:5836  
    ##  10004  :    1   10004  :  905   Mean   :  99107   D:5892  
    ##  10005  :    1   10005  :  719   3rd Qu.: 117060   E:5855  
    ##  10006  :    1   10006  :  584   Max.   :2977127   F:5979  
    ##  (Other):40994   (Other):31982                     G:5805
    

    除了Energy,所有列都是因子。

    【讨论】:

      猜你喜欢
      • 2018-04-15
      • 1970-01-01
      • 2015-05-25
      • 2015-03-06
      • 1970-01-01
      • 2018-06-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多