使用OR选择

时间:2019-07-03 15:26:02

标签: r data.table

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

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

我需要执行快速的二进制搜索以查找“开始”列或“结束”列中的哪些记录等于一个值(或多个),例如,在SQL中,将是这样的: / p>

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");

我需要在开始或结束的值是检查行startcheck或endcheck的值的行中搜索记录。

我现在正在做的是:

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

结果将是:

enter image description here

但是此搜索还不够快,如果我没记错的话,它不会使用二进制键。

3 个答案:

答案 0 :(得分:2)

我们可以使用%in%代替====用于只有一个要比较的元素或整个列用于元素比较的情况。如果有多个元素,请使用%in%

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

答案 1 :(得分:1)

在此示例中,您可以使用%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都没有关系, 就像未激活索引一样。

关于如何优化此搜索效果的任何想法?

-编辑-

我找到了一种解决方案,可以通过melt函数将搜索列(开始和结束)转换为行:

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

结果是这样的结构:

enter image description here

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

setkey(channelids, value);

搜索速度更快,并且对象比我测试过的其他方法还小。

答案 2 :(得分:0)

其他一些方法和时间安排实际上取决于您的实际尺寸。如评论中所述,重复对象对1条记录多次运行查询,而这里需要在数据集中搜索多个记录。

数据:

#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~