【问题标题】:Perform an R data.table binary search with OR select使用 OR select 执行 R data.table 二进制搜索
【发布时间】:2019-11-14 08:10:33
【问题描述】:

我正在使用一个名为“lines”的 data.table,它使用 2 个二进制索引创建

setkeyv(lines,c("start","end"))

我需要执行快速二分搜索来查找“开始”列或“结束”列中的哪些记录等于一个值(或多个),例如,在 SQL 中它会是这样的:

select column1, column2, column3 from lines where start = 2 OR end = 2

在带有二进制索引的 R data.tables 中,我可以这样做

lines[.(2,2)]

但是这句话等于start = 2 AND end = 2,这不是我需要的。

我知道用这样的方法可以做到这一点,但它不够快,而且它不使用二进制搜索。

line[(start == c(2,3) | end == c(2,3)];

如何根据此要求执行快速搜索?

我需要做的一个简单示例。

lines <- data.table(id = c(1,2,3,4,5,6,7), start = c(901,902,903,904,905,906,907), end = c(101,102,103,104,105,106,107));

checklines <- data.table(id = c(1,2,3,4), startcheck = c(330,902,903,101), endcheck = c(106,400,907));

setkeyv(lines, c("start","end");

我需要搜索start OR end的值为checklines startcheck或endcheck的值的行中的记录。

我现在做的是:

lines[start %in% c(checklines$startcheck,checklines$endcheck) | end %in% c(checklines$startcheck,checklines$endcheck)];

结果将是:

但是这个搜索速度不够快,如果我没记错的话,它不使用二进制键。

【问题讨论】:

标签: r data.table


【解决方案1】:

我们可以使用%in% 代替==== 用于当只有一个元素要比较或整列进行元素比较时。当有多个元素时,使用%in%

line[(start %in% c(2,3) | end %in% c(2,3))];

【讨论】:

  • 确实如此,谢谢。但是该代码不执行二进制搜索,对吗?我正在寻找快速的东西,例如二进制搜索,因为 data.table 包含数百万条记录。
  • @Carlos 您能否提供一个可重现的小示例进行测试
  • 我在我的问题中添加了一个简单的例子。
【解决方案2】:

测试这个例子你可以用%in%子句检查,如果启用索引,性能提升是显着的(它使用二进制索引)

set.seed(108)
N = 1e8
DT = setDT(list(sample(N/10, N, TRUE), sample(letters, N, TRUE)))
setindexv(DT, c("V1","V2"))
options("datatable.use.index"=TRUE)
system.time(ans1<-DT[V1 %in% 1000:1002 & V2 %in% c("a","b","c")])
# user system elapsed
# 0.001 0.000 0.002
options("datatable.use.index"=FALSE)
system.time(ans2<-DT[V1 %in% 1000:1002 & V2 %in% c("a","b","c")])
# user system elapsed
# 4.051 0.848 4.899

但是,用 |

改变 &
system.time(ans1<-DT[V1 %in% 1000:1002 | V2 %in% c("a","b","c")])

索引是ON还是OFF都没有关系, 表现得好像索引没有被激活。

关于如何优化此搜索的性能的任何想法?

-- 编辑--

我找到了一个解决方案,将搜索列(开始和结束)转换为带有融化功能的行:

channelids <<- melt(lines[,c("id","start","end")], id=c("id"));

结果是这样的结构:

现在,包括对象的二进制索引,

setkey(channelids, value);

与我测试过的其他方法相比,搜索速度更快,对象也更小。

【讨论】:

    【解决方案3】:

    其他一些方法和时间实际上取决于您的实际尺寸。正如评论中提到的,骗子对一条记录多次运行查询,而这里需要在数据集中搜索多条记录。

    数据:

    #generate sample datasets
    library(data.table)
    set.seed(0L)
    nr <- 1e6
    lines <- data.table(start=sample(1:1e4, nr, TRUE), end=sample(1:1e4, nr, TRUE))[, id := .I]
    checklines <- unique(data.table(start=sample(1:1000, 1000, TRUE), end=sample(1:1000, 1000, TRUE))[, id := .I])
    checks <- c(checklines$start, checklines$end)
    
    DT <- copy(lines)
    sl <- copy(lines)  
    el <- copy(lines) 
    

    计时码:

    bench::mark(
        mtd0={
            setkey(lines, start, end)
            lines[start %in% checks | end %in% checks]
        },
        mtd2={
            setkey(DT, start)
            ix1 <- DT[.(checks), id]
            setkey(DT, end)
            ix2 <- DT[.(checks), id]
            DT[unique(c(ix1, ix2))]
        },
        mtd3={
            setkey(sl, start)
            setkey(el, end)
            lines[unique(c(sl[.(checks), id], el[.(checks), id]))]
        },
        check=FALSE #ordering difference
    )
    

    时间安排:

    # A tibble: 3 x 14
      expression      min     mean   median      max `itr/sec` mem_alloc  n_gc n_itr total_time result                     memory              time    gc              
      <chr>      <bch:tm> <bch:tm> <bch:tm> <bch:tm>     <dbl> <bch:byt> <dbl> <int>   <bch:tm> <list>                     <list>              <list>  <list>          
    1 mtd0         36.8ms   37.2ms   37.2ms   37.3ms      26.9    36.9MB     8     5      186ms <data.table [165,061 x 3]> <Rprofmem [19 x 3]> <bch:t~ <tibble [13 x 3~
    2 mtd2         49.4ms   51.1ms   50.4ms     57ms      19.6    20.5MB     3     7      358ms <data.table [165,061 x 3]> <Rprofmem [43 x 3]> <bch:t~ <tibble [10 x 3~
    3 mtd3         20.8ms   21.7ms   21.4ms   22.8ms      46.1    20.5MB     4    14      303ms <data.table [165,061 x 3]> <Rprofmem [43 x 3]> <bch:t~ <tibble [18 x 3~
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-01-27
      • 1970-01-01
      • 2020-10-25
      • 2013-12-12
      • 1970-01-01
      • 2010-11-01
      • 2012-06-27
      • 1970-01-01
      相关资源
      最近更新 更多