Data.table 在筛选数据表时,链接优于ANDing的性能优势
我习惯于将类似的任务组合成一行。例如,如果我需要在数据表中筛选Data.table 在筛选数据表时,链接优于ANDing的性能优势,data.table,r,Data.table,R,我习惯于将类似的任务组合成一行。例如,如果我需要在数据表中筛选a、b和c,我会将它们与and一起放在一个[]中。昨天,我注意到,在我的特殊情况下,这是难以置信的缓慢和测试链接过滤器代替。我在下面举了一个例子 首先,我给随机数生成器添加种子,加载并创建一个虚拟数据集 #设置RNG种子 种子集(-1) #加载库 库(数据表) #创建数据表 dt expr min lq平均中值uq max #>链式过滤器()25.17734 31.24489 39.44092 37.53919 43.51588 78
a
、b
和c
,我会将它们与and一起放在一个[]
中。昨天,我注意到,在我的特殊情况下,这是难以置信的缓慢和测试链接过滤器代替。我在下面举了一个例子
首先,我给随机数生成器添加种子,加载并创建一个虚拟数据集
#设置RNG种子
种子集(-1)
#加载库
库(数据表)
#创建数据表
dt expr min lq平均中值uq max
#>链式过滤器()25.17734 31.24489 39.44092 37.53919 43.51588 78.12492
#>和_filter()92.6641112.06136 130.92834 127.64009 149.17320 206.61777
#>内瓦尔cld
#>100 a
#>100 b
由(v0.3.0)于2019-10-25创建
在这种情况下,链接将运行时间减少约70%。为什么会这样?我的意思是,在数据表中,引擎盖下面发生了什么?我没有看到任何反对使用&
的警告,所以我很惊讶差异如此之大。在这两种情况下,他们评估相同的条件,所以这不应该是一个区别。在AND情况下,&
是一个快速运算符,然后它只需过滤数据表一次(即,使用ANDs产生的逻辑向量),而不是在链式情况下过滤三次
奖金问题
这个原则一般适用于数据表操作吗?模块化任务总是一种更好的策略吗?大多数情况下,答案在阿莱迪的评论中给出:数据的“链接方法”。在这种情况下,表比“anding方法”更快,因为链接一个接一个地运行条件。由于每一步都减少了
数据表的大小,因此下一步需要评估的数据就更少了。“Anding”每次评估全尺寸数据的条件
我们可以用一个例子来说明这一点:当单个步骤没有减小数据表的大小时(即,两种方法的检查条件相同):
正如您在这里看到的,在这种情况下,anding方法的速度是的2.43倍。这意味着链接实际上增加了一些开销,这意味着通常的anding应该更快除非条件是逐步减小数据表的大小。从理论上讲,链接方法甚至可能更慢(即使将开销放在一边),也就是说,如果某个条件会增加数据的大小。但实际上我认为这是不可能的,因为在data.table
中不允许循环使用逻辑向量。我想这回答了你的奖金问题
为了进行比较,我的机器上带有工作台的原始功能:
res <- bench::mark(
chain = chain_filter_original(),
and = and_filter_original()
)
summary(res)
#> # A tibble: 2 x 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 chain 29.6ms 30.2ms 28.5 79.5MB 7.60
#> 2 and 125.5ms 136.7ms 7.32 228.9MB 7.32
summary(res, relative = TRUE)
#> # A tibble: 2 x 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 chain 1 1 3.89 1 1.04
#> 2 and 4.25 4.52 1 2.88 1
res#A tibble:2 x 6
#>表达式最小中位数`itr/sec`mem_alloc`gc/sec`
#>
#>1条链条29.6ms 30.2ms 28.5 79.5MB 7.60
#>2和125.5毫秒136.7毫秒7.32 228.9 MB 7.32
摘要(res,relative=TRUE)
#>#A tibble:2 x 6
#>表达式最小中位数`itr/sec`mem_alloc`gc/sec`
#>
#>1链条1 3.89 1 1.04
#>2及4.25 4.52 1 2.88 1
我也这么认为,我也有同样的想法。根据我的经验,在一般操作中可以观察到链式加速。虽然data.tavle确实对这种情况进行了一些优化(这本身就是一项壮举,与基本R相比是一个巨大的改进!),但一般来说,a&B&C&D将在组合结果和过滤之前评估所有N个逻辑条件。然而,通过链接,第二个、第三个和第四个逻辑调用仅计算n次(在哪里n@MichaelChirico哇!这太奇怪了!我不知道为什么,但是我只是假设它会像C++的短路径一样在MichaelChirico的评论后面继续,你可以通过以下方式来制作一个类似的<代码>基础<代码>矢量观察:<代码> ChanyVEC @ MichaelChirico Ah,我明白了。链中的数据表要小得多,因此可以更快地评估条件并进行筛选?这很有意义。感谢您的见解!
res <- bench::mark(
chain = chain_filter(),
and = and_filter()
)
summary(res)
#> # A tibble: 2 x 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 chain 299ms 307ms 3.26 691MB 9.78
#> 2 and 123ms 142ms 7.18 231MB 5.39
summary(res, relative = TRUE)
#> # A tibble: 2 x 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 chain 2.43 2.16 1 2.99 1.82
#> 2 and 1 1 2.20 1 1
res <- bench::mark(
chain = chain_filter_original(),
and = and_filter_original()
)
summary(res)
#> # A tibble: 2 x 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 chain 29.6ms 30.2ms 28.5 79.5MB 7.60
#> 2 and 125.5ms 136.7ms 7.32 228.9MB 7.32
summary(res, relative = TRUE)
#> # A tibble: 2 x 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 chain 1 1 3.89 1 1.04
#> 2 and 4.25 4.52 1 2.88 1