按升序/降序快速排序data.table

时间:2012-12-03 14:27:47

标签: r performance data.table

我有一个data.table,大约有300万行和40列。我想按照以下sql模拟代码组中的降序对此表进行排序:

sort by ascending Year, ascending MemberID, descending Month 

data.table中是否有相同的方法来执行此操作?到目前为止,我必须将其分解为两个步骤:

setkey(X, Year, MemberID)

速度非常快,只需几秒钟。

X <- X[,.SD[order(-Month)],by=list(Year, MemberID)]

此步骤需要更长时间(5分钟)。

更新: 有人发表评论X <- X[sort(Year, MemberID, -Month)]后来被删除了。这种方法似乎要快得多:

user  system elapsed 
5.560  11.242  66.236 

我的方法:setkey()然后订购(-Month)

   user  system elapsed 
816.144   9.648 848.798 

我现在的问题是:如果我想按年份汇总,在排序后的MemberId和Month(Year,MemberID,Month),data.table是否识别排序顺序?

更新2:回应Matthew Dowle:

使用Year,MemberID和Month的setkey后,每组仍有多个记录。我想要的是总结每个小组。我的意思是:如果我使用X [order(Year,MemberID,Month)],求和是否利用data.table的二进制搜索功能:

monthly.X <- X[, lapply(.SD[], sum), by = list(Year, MemberID, Month)]

更新3:Matthew D提出了几种方法。第一种方法的运行时间比order()方法更快:

   user  system elapsed 
  7.910   7.750  53.916 

马修:让我感到惊讶的是转换月份的标志大部分时间。没有它,setkey的速度非常快。

2 个答案:

答案 0 :(得分:72)

2014年6月5日更新:

data.table v1.9.3的当前开发版本实现了两个新功能,即:setordersetorderv,它们完全符合您的要求。这些函数通过引用重新排序data.table ,并选择按顺序选择每列的升序或降序。查看?setorder了解详情。

此外,DT[order(.)]默认情况下也已优化为使用data.table内部快速订单而不是base:::order。与setorder不同,这将创建数据的完整副本,因此内存效率较低,但仍比使用base的顺序运行速度快几个数量级。

基准:

以下是使用setorder,data.table的内部快速订单和base:::order来说明速度差异的说明:

require(data.table) ## 1.9.3
set.seed(1L)
DT <- data.table(Year     = sample(1950:2000, 3e6, TRUE), 
                 memberID = sample(paste0("V", 1:1e4), 3e6, TRUE), 
                 month    = sample(12, 3e6, TRUE))

## using base:::order
system.time(ans1 <- DT[base:::order(Year, memberID, -month)])
#   user  system elapsed 
# 76.909   0.262  81.266 

## optimised to use data.table's fast order
system.time(ans2 <- DT[order(Year, memberID, -month)])
#   user  system elapsed 
#  0.985   0.030   1.027

## reorders by reference
system.time(setorder(DT, Year, memberID, -month))
#   user  system elapsed 
#  0.585   0.013   0.600 

## or alternatively
## setorderv(DT, c("Year", "memberID", "month"), c(1,1,-1))

## are they equal?
identical(ans2, DT)    # [1] TRUE
identical(ans1, ans2)  # [1] TRUE

根据这些数据,基准测试表明,data.table的顺序比base:::order 快〜79倍setorder比<{>>快135倍 base:::order在这里。

data.table总是在C语言环境中排序/排序。如果您需要在其他语言环境中订购,那么您是否需要使用DT[base:::order(.)]

所有这些新的优化和功能共同构成FR #2405bit64::integer64 support also has been added


  

注意:请参阅早期答案和更新的历史记录/修订版。

答案 1 :(得分:13)

评论是我的,所以我会发布答案。我删除它是因为我无法测试它是否与您已有的相同。很高兴听到它更快。

X <- X[order(Year, MemberID, -Month)]

总结不应取决于行的顺序。