【问题标题】:What's the fastest way to subset a data.table?对 data.table 进行子集化的最快方法是什么?
【发布时间】:2014-05-20 09:24:05
【问题描述】:

在我看来,处理data.table 的行/列子集的最快方法是使用连接和nomatch 选项。

这对吗?

DT = data.table(rep(1:100, 100000), rep(1:10, 1000000))
setkey(DT, V1, V2)
system.time(DT[J(22,2), nomatch=0L])
# user  system elapsed 
# 0.00    0.00    0.01 
system.time(subset(DT, (V1==22) & (V2==2)))
# user  system elapsed 
# 0.45    0.21    0.67 

identical(DT[J(22,2), nomatch=0L],subset(DT, (V1==22) & (V2==2)))
# [1] TRUE

我对基于二分搜索的快速连接也有一个问题:我找不到一种方法来选择一维中的所有项目。

说如果我想随后做:

DT[J(22,2), nomatch=0]  # subset on TWO dimensions
DT[J(22,), nomatch=0]   # subset on ONE dimension only
# Error in list(22, ) : argument 2 is empty

无需将键重新设置为仅一维(因为我处于循环中,我不想每次都休息键)。

【问题讨论】:

  • 这里有很好的关于常见 data.table 操作(包括子集)时序的文档:datatable.r-forge.r-project.org/datatable-timings.pdf
  • 我查看了文档第 1.1 段提取。在我看来,除非添加 nomatch 选项,否则提取并不完全是子集。这也没有解决同时的 1 维和 2 维子集(请参阅我的更新问题)。
  • @tucson 这是两个完全不同的问题,需要不同的答案,所以他们应该有自己的帖子,但没关系。有关第二个问题的解决方案,请参阅 stackoverflow.com/questions/15597685/…

标签: r data.table


【解决方案1】:

data.table 进行子集化的最快方法是什么?

使用基于二分搜索的子集功能是最快的。请注意,子集需要选项nomatch = 0L,以便仅返回匹配结果。

如何仅在设置两个键的情况下通过其中一个键进行子集化?

如果您在 DT 上设置了两个键,并且您想通过 第一个键 子集,那么您只需提供 J(.) 中的第一个值,不需要为第二个键提供任何东西。那就是:

# will return all columns where the first key column matches 22
DT[J(22), nomatch=0L] 

如果您想通过第二个键进行子集化,那么您现在必须为第一个键提供所有唯一值。那就是:

# will return all columns where 2nd key column matches 2
DT[J(unique(V1), 2), nomatch=0L]

这也显示在in this SO post。虽然我更喜欢 DT[J(, 2)] 来处理这种情况,因为这看起来很直观。

还有一个待处理的功能请求,FR #1007 用于实现辅助键,完成后会处理此问题。

这是一个更好的例子:

DT = data.table(c(1,2,3,4,5), c(2,3,2,3,2))
DT
#    V1 V2
# 1:  1  2
# 2:  2  3
# 3:  3  2
# 4:  4  3
# 5:  5  2
setkey(DT,V1,V2)
DT[J(unique(V1),2)]
#    V1 V2
# 1:  1  2
# 2:  2  2
# 3:  3  2
# 4:  4  2
# 5:  5  2
DT[J(unique(V1),2), nomatch=0L]
#    V1 V2
# 1:  1  2
# 2:  3  2
# 3:  5  2
DT[J(3), nomatch=0L]
#    V1 V2
# 1:  3  2

总结:

# key(DT) = c("V1", "V2")

# data.frame                        |             data.table equivalent
# =====================================================================
# subset(DF, (V1 == 3) & (V2 == 2)) |            DT[J(3,2), nomatch=0L]
# subset(DF, (V1 == 3))             |              DT[J(3), nomatch=0L]
# subset(DF, (V2 == 2))             |  DT[J(unique(V1), 2), nomatch=0L]

【讨论】:

  • 要记住的一个重要警告是,对于单个子集 DT[V1 == 3 & V2 == 2] 将比设置密钥和执行二分搜索更快 - 所以二分搜索只有在密钥已经存在时才有意义设置,或者您根据setkey进行多次搜索
猜你喜欢
  • 2011-09-29
  • 2013-05-13
  • 2015-09-16
  • 2020-07-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多