有没有更好的方法将一个向量的每个元素匹配到一组定义的区间?

问题描述 投票:0回答:1

我有一组定义的区间,我需要根据向量的每个元素所在的区间对其进行分类。下面是一个例子。因为我的数据会非常大,我想知道是否有更有效的方法来实现。

library(dplyr)
Intrevals <- data.frame(start = c( 3, 6, 10, 58, 78), end = c(4, 8, 46, 68, 84 ), catg = c("F", "R", "O", "S", "X"))
x = data.frame( unit = c(1:100), value = sample(1:84, 100, replace = TRUE))
E = x %>%
  tidyr::crossing(Intrevals) %>%
  dplyr::mutate(flag = ifelse((value >= start) & (value < end), 1, 0)) %>%
  dplyr::filter(flag == 1)

谢谢你的建议。

r dplyr data.table tidy
1个回答
1
投票

你可以在基础R中使用 cut. 由于你的 sample 语句产生的值超出了范围,我修改了它,使所有值都在其中一个范围内。

Intervals <- data.frame(start = c( 3, 6, 10, 58, 78), 
    end = c(4, 8, 46, 68, 84 ), 
    catg = c("F", "R", "O", "S", "X"))
x = data.frame( unit = c(1:100), value = sample(3:84, 100, replace = TRUE))
B = c(Intervals$start[1], Intervals$end)
cut(x$value, breaks=B, labels=Intervals$catg, include.lowest=T)

  [1] X O O O X S O O O O S X X O O X O O O O S O O O O O O S X R X O R S O S S S O
 [40] X O X R S O S S F O X X O S S F S O O X O S O S O O O O F S O O O O O O O S X
 [79] S O O S X X X F O X X O O R O X O O O X X S
Levels: F R O S X

1
投票

这里有4个选项,使用 data.table:

首先,设置一些键 IntervalsDT 对于方案1-3。

setDT(Intervals, key=c("start","end"))
DT <- as.data.table(x, key="value")

(1) 使用非等价加入和 by=.EACHI:

DT[, catg1 := Intervals[DT, on=.(start<=value, end>=value), by=.EACHI, catg]$catg]

(2) 使用2个滚动连接来寻找 catg 基于 startend 且只有当两者相同时,才在区间内。

DT[, catg2 := {
    s <- Intervals[DT, on=.(start=value), roll=Inf, mult="first", catg]
    e <- Intervals[DT, on=.(end=value), roll=-Inf, mult="last", catg]
    fifelse(s==e, s, NA_character_)
}]

3)同样是滚动连接,但要翻转左右表,因为一个表比另一个表短,可能会更快。

Intervals[, sr := DT[.SD, on=.(value=start), roll=-Inf, mult="first", which=TRUE]]
Intervals[, er := DT[.SD, on=.(value=end), roll=Inf, mult="last", which=TRUE]]
ix <- Intervals[, .(lst=seq(er ,sr), values=rep(catg, er - sr + 1L)), 1L:nrow(Intervals)]
DT[, catg3 := replace(rep(NA_character_, .N), ix$lst, ix$values)]

4) 使用 foverlaps:

DT2 <- setkey(as.data.table(x)[, c("start", "end") := .(value, value)], start, end)
DT[, catg4 := foverlaps(DT2, Intervals)$catg]   #using DT and not DT2 for checking correctness

输出头。

     unit value catg catg2 catg3 catg4
  1:    8     1 <NA>  <NA>  <NA>  <NA>
  2:   82     1 <NA>  <NA>  <NA>  <NA>
  3:  100     1 <NA>  <NA>  <NA>  <NA>
  4:   49     2 <NA>  <NA>  <NA>  <NA>
  5:    1     3    F     F     F     F
  6:    2     3    F     F     F     F
  7:    3     4    F     F     F     F
  8:    4     4    F     F     F     F
  9:   45     6    R     R     R     R
 10:   18     7    R     R     R     R
 11:   81    10    O     O     O     O
 12:   59    13    O     O     O     O
 13:   65    13    O     O     O     O

数据。

library(data.table)
set.seed(0L)
Intervals <- data.frame(start = c( 3, 6, 10, 58, 78), end = c(4, 8, 46, 68, 84 ), 
    catg = c("F", "R", "O", "S", "X"))
x = data.frame( unit = c(1:100), value = c(3,3,4,4,sample(1:84, 96, replace = TRUE)))

有兴趣了解每个选项的执行情况。

© www.soinside.com 2019 - 2024. All rights reserved.