我们有一个已排序的向量foo
,对于每个元素i
,我们希望找到最大的j
foo[j]-foo[i] < 10
。例如
foo <- c(1,2,5,7,13,17,25,33,85)
答案是:
bar <- c(4,4,5,5,6,7,8,8,9)
(对于i=1
,自j
以来最大的foo[4]-foo[1]=7-1<10
为4。因此bar
的第一项是4)。
我们可以使用bar
和for
循环轻松计算while
。但我正在寻找一个有效的代码R.任何想法?
答案 0 :(得分:3)
使用非equi连接更新解决方案:
最近,非equi 加入在current development version of data.table, v1.9.7中实施。使用此功能非常简单:
require(data.table) # v1.9.7+
dt1 = data.table(x=foo)
dt2 = data.table(y=foo+10L)
dt1[dt2, on=.(x < y), mult="last", which=TRUE]
# [1] 4 4 5 5 6 7 8 8 9
在100,000个元素上,这比foverlaps
:
set.seed(45L)
foo <- sort(sample(1e6, 1e5, FALSE))
dt1 = data.table(x=foo)
dt2 = data.table(y=foo+10L)
system.time(ans <- dt1[dt2, on=.(x < y), mult="last", which=TRUE])
# user system elapsed
# 0.011 0.001 0.011
请注意,此操作可以直接完成,如下所示:
ans <- data.table(x=foo)[.(y=x+10L), on=.(x < y), mult="last", which=TRUE]
使用foverlaps
的旧方法:
这是一种可能更好地扩展的方法。使用foverlaps()
版本1.9.4中的重叠范围连接函数data.table
:
require(data.table) ## 1.9.4+
x = data.table(start=foo, end=foo+9L)
lookup = data.table(start=foo, end=foo)
setkey(lookup) ## order doesn't change, as 'foo' is already sorted
foverlaps(x, lookup, mult="last", which=TRUE)
# [1] 4 4 5 5 6 7 8 8 9
计时100,000个数字:
set.seed(45L)
foo <- sort(sample(1e6, 1e5, FALSE))
arun <- function(foo) {
x = data.table(start=foo, end=foo+9L)
lookup = data.table(start=foo, end=foo)
setkey(lookup)
foverlaps(x, lookup, mult="last", which=TRUE)
}
system.time(arun(foo))
# user system elapsed
# 0.142 0.009 0.153
答案 1 :(得分:1)
尝试
sapply(foo, function(x) {m1 <-foo-x; which.max(m1[m1<10])})
#[1] 4 4 5 5 6 7 8 8 9
答案 2 :(得分:1)
假设没有NA
值:
apply(as.matrix(dist(foo)), 1, function(x) {
which.max(cumsum(x < 10))
})
#1 2 3 4 5 6 7 8 9
#4 4 5 5 6 7 8 8 9
这是一个仅使用稀疏矩阵的解决方案:
library(spam)
res <- apply.spam(as.spam(dist(foo)), 2, function(x) {
test <- cumsum(x < 10)
if (sum(test) > 0 ) which.max(test) else (0)
}) + seq_along(foo)
res[length(res)] <- length(res)
#[1] 4 4 5 5 6 7 8 8 9