R 仅按2列键的第2列对data.table进行子集设置,使用二进制搜索而不是向量扫描
我最近在R 仅按2列键的第2列对data.table进行子集设置,使用二进制搜索而不是向量扫描,r,data.table,R,Data.table,我最近在data.table中发现了二进制搜索。如果表格按多个键排序,是否可以仅按第二个键进行搜索 DT = data.table(x=sample(letters,1e7,T),y=sample(1:25,1e7,T),rnorm(1e7)) setkey(DT,x,y) #R> DT[J('x')] # x y V3 # 1: x 1 0.89109 # 2: x 1 -2.01457 # --- #3
data.table
中发现了二进制搜索。如果表格按多个键排序,是否可以仅按第二个键进行搜索
DT = data.table(x=sample(letters,1e7,T),y=sample(1:25,1e7,T),rnorm(1e7))
setkey(DT,x,y)
#R> DT[J('x')]
# x y V3
# 1: x 1 0.89109
# 2: x 1 -2.01457
# ---
#384922: x 25 0.09676
#384923: x 25 0.25168
#R> DT[J('x',3)]
# x y V3
# 1: x 3 -0.88165
# 2: x 3 1.51028
# ---
#15383: x 3 -1.62218
#15384: x 3 -0.63601
编辑:感谢@Arun
R> system.time(DT[J(unique(x), 25)])
user system elapsed
0.220 0.068 0.288
R> system.time(DT[y==25])
user system elapsed
0.268 0.092 0.359
是的,您可以将所有值传递给第一个键值,并将第二个键的特定值传递给子集
DT[J(unique(x), 25), nomatch=0]
如果需要在第二个键中按多个值进行子集划分(例如,相当于DT[y%in%25:24]
),则更通用的解决方案是使用CJ
DT[CJ(unique(x), 25:24), nomatch=0]
默认情况下,CJ
会对列进行排序,并为所有列设置键,这意味着结果也会被排序。如果不需要这样做,则应使用sorted=FALSE
DT[CJ(unique(x), 25:24, sorted=FALSE), nomatch=0]
还有一个功能请求,要求将来向data.table
添加辅助键。我相信计划是添加一个新函数set2key
还有merge
,它有一个数据表的方法。它为您在其中构建辅助密钥,因此应该比基本合并更快。请参见?merge.data.table
基于我编写的以下函数:
create_index = function(dt, ..., verbose = getOption("datatable.verbose")) {
cols = data.table:::getdots()
res = dt[, cols, with=FALSE]
res[, i:=1:nrow(dt)]
setkeyv(res, cols, verbose = verbose)
}
JI = function(index, ...) {
index[J(...),i]$i
}
以下是我的系统上DT较大(1e8行)的结果:
系统时间(DT[J(“c”))
用户系统运行时间
0.168 0.136 0.306
>系统时间(DT[J(唯一(x),25)])
用户系统运行时间
2.472 1.508 3.980
>系统时间(DT[y==25])
用户系统运行时间
4.532 2.149 6.674
>系统时间(IDX_y系统时间(DT[JI(IDX_y,25)])
用户系统运行时间
0.512 0.320 0.831
如果您多次使用索引,它是值得的。谢谢,与通常的数据相比,它看起来有点低效。表性能,虽然比R向量搜索更好…是的,我想不出更好的方法。但我不认为它一般是打算这样使用的。例如,如果您检查,
DF[DF$x==“a”&DF$y==“25”
和DT[J(“a”,25)]
你会看到区别的。当然,但是你必须再次排序…如果我们想排序的话,任何东西都可以。DF[DF$x==“a”| DF$y==“25”,]
(或者代替和)@Arun已经在nomatch=0
中编辑过了。这是需要的,对吧?以前没有发现过。@MatthewDowle我不知道哪种方法会更好(为了提高速度和/或增加功能)但是J中的命名列可以定义要使用的键
将是一个非常方便且功能强大的选项,再次感谢您的数据表
!谢谢。我已经扩展了第n个键的功能:现在在Rdatatable
Github页面中的其中一个键中介绍了这一功能。
> system.time(DT[J("c")])
user system elapsed
0.168 0.136 0.306
> system.time(DT[J(unique(x), 25)])
user system elapsed
2.472 1.508 3.980
> system.time(DT[y==25])
user system elapsed
4.532 2.149 6.674
> system.time(IDX_y <- create_index(DT, y))
user system elapsed
3.076 2.428 5.503
> system.time(DT[JI(IDX_y, 25)])
user system elapsed
0.512 0.320 0.831