我有一组定义的区间,我需要根据向量的每个元素所在的区间对其进行分类。下面是一个例子。因为我的数据会非常大,我想知道是否有更有效的方法来实现。
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中使用 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
这里有4个选项,使用 data.table
:
首先,设置一些键 Intervals
和 DT
对于方案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
基于 start
或 end
且只有当两者相同时,才在区间内。
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)))
有兴趣了解每个选项的执行情况。