当前位置: 首页 > 知识库问答 >
问题:

data.table: 矢量扫描 v 二进制搜索与数字列 - 超慢设置键

马俊
2023-03-14

我正在尝试找到用几个数字列子集大数据集的最快方法。正如data.table所promise的,进行二进制搜索所需的时间比矢量扫描快得多。但是,二进制搜索需要事先执行setkey。正如您在这段代码中看到的,它需要非常长的时间!一旦您考虑到这段时间,矢量扫描就快得多:

set.seed(1)
n=10^7
nums <- round(runif(n,0,10000))
DT = data.table(s=sample(nums,n), exp=sample(nums,n), 
         init=sample(nums,n), contval=sample(nums,n))
this_s = DT[0.5*n,s] 
this_exp = DT[0.5*n,exp]
this_init = DT[0.5*n,init]
system.time(ans1<-DT[s==this_s&exp==this_exp&init==this_init,4,with=FALSE])
#   user  system elapsed 
#   0.65    0.01    0.67 
system.time(setkey(DT,s,exp,init))
#   user  system elapsed 
#  41.56    0.03   41.59 
system.time(ans2<-DT[J(this_s,this_exp,this_init),4,with=FALSE])
#   user  system elapsed 
#    0       0       0 
identical(ans1,ans2)
# [1] TRUE

我做错了什么吗?我已经阅读了data.table常见问题解答等。任何帮助都将不胜感激。

非常感谢。

共有1个答案

东方权
2023-03-14

该行:

nums <- round(runif(n,0,10000))

数字保留为类型数字而不是整数。这有很大的不同。数据表常见问题解答和介绍面向整数字符列;在这些类型上,您不会看到 setkey 很慢。例如:

nums <- as.integer(round(runif(n,0,10000)))
...
setkey(DT,s,exp,init)  # much faster now

还有两点...

首先,在当前的数据开发版本中,排序/排序操作要快得多。表v1.8.11。@jihoward关于数字列的排序是一个更耗时的操作的观点是正确的。但是,在1.8.11中,它仍然快了大约5-8倍(因为实现了6次基数顺序,请查看本文)。比较1.8.10和1.8.11中<code>设置键<code>操作所需的时间:

# v 1.8.11
system.time(setkey(DT,s,exp,init))
#    user  system elapsed 
#   8.358   0.375   8.844 

# v 1.8.10
system.time(setkey(DT,s,exp,init))
#   user  system elapsed 
# 66.609   0.489  75.216 

这是我的系统8.5倍的改进。所以,我的猜测是,这大约需要4.9秒。

第二,正如@Roland提到的,如果你的目标是执行几个子集化,而这就是你要做的全部,那么当然做setkey是没有意义的,因为它必须找到列的顺序,然后重新排序整个data.table(通过引用,以便内存占用非常少,查看这篇文章了解更多关于setkey的信息)。

 类似资料:
  • 我有一个严格按递减顺序排序的数组和一个元素;我想找到数组中最大元素的索引,该元素小于val(如果val已经存在,则为相等),并且我想在时间内完成此操作。和执行upper_bound()不是一个选项。 例如,如果数组为{10,5,3,1}而val为6,则函数应返回1。 我对迭代器是个新手,尝试过在upper_bound()中添加比较函数来使其工作,但失败了。我该怎么处理这件事。 注意:我检查了类似的

  • 问题内容: 程序从经过排序的字符串的txt文件中读取,并使用顺序的,迭代的二进制和递归的二进制存储在数组中,然后在数组中搜索位置以及查找该单词所需的迭代次数。当我尝试将数组中的单词与用户输入的单词进行比较时出现错误。不知道为什么。2)希望有人可以解释迭代二进制和递归二进制之间的区别。3)为什么需要这样做… SearchString si = new SearchString(); 程序在下面… }

  • 问题内容: 我知道索引在内部是B树或类似的树结构。假设索引是为3列构建的,我希望Postgres执行以下操作: 在该B树中找到键[a = 10,b = 20,c = 30], 扫描下10个条目并返回它们。 如果索引只有一列,则解决方案显而易见: 但是,如果有更多的列,解决方案将变得更加复杂。对于2列: 3栏: 请注意查询: 是 不正确的 ,因为它将例如过滤掉[a = 11,b = 10,c = 1

  • 二进制搜索是一种快速搜索算法,运行时复杂度为Ο(log n)。 这种搜索算法的工作原则是分而治之。 为使此算法正常工作,数据收集应采用排序形式。 二进制搜索通过比较集合的最中间项来查找特定项。 如果匹配发生,则返回项目的索引。 如果中间项大于项,则在中间项左侧的子阵列中搜索项。 否则,在中间项右侧的子阵列中搜索项。 该过程也在子阵列上继续,直到子阵列的大小减小到零。 二进制搜索如何工作? 要使二进

  • 给定二叉查找树(BST)和整数val的根。 在BST中找到该节点的值等于val的节点,并返回以该节点为根的子树。如果这样的节点不存在,则返回null。 为什么'ans=root'不起作用??

  • 问题内容: 我有一个排序的数组,想要对它进行二进制搜索。 所以我想问一下Swift库中是否已有诸如sort等的东西?还是有类型独立版本可用? 当然,我可以自己编写它,但是我想避免再次发明轮子。 问题答案: 这是使用二进制搜索的通用方法: