2012-11-20 27 views
17

R中的大findInterval()函数使用左关闭在其vec参数子间隔,如图其文档:findInterval()与右关闭间隔

如果i <- findInterval(x,v),我们有v[i[j]] <= x[j] < v[i[j] + 1]

如果我想要右闭合子区间,我有什么选择?我想出的最好的是这样的:

findInterval.rightClosed <- function(x, vec, ...) { 
    fi <- findInterval(x, vec, ...) 
    fi - (x==vec[fi]) 
} 

另一种也适用:

findInterval.rightClosed2 <- function(x, vec, ...) { 
    length(vec) - findInterval(-x, -rev(vec), ...) 
} 

这里有一个小测试:

x <- c(3, 6, 7, 7, 29, 37, 52) 
vec <- c(2, 5, 6, 35) 
findInterval(x, vec) 
# [1] 1 3 3 3 3 4 4 
findInterval.rightClosed(x, vec) 
# [1] 1 2 3 3 3 4 4 
findInterval.rightClosed2(x, vec) 
# [1] 1 2 3 3 3 4 4 

但我想看到的任何其他解决方案,如果有更好的。通过“更好”,我的意思是“以某种方式更令人满意”或“不觉得自己像个混蛋”,或者甚至“更有效率”。 =)

(请注意,有一个rightmost.closed参数findInterval(),但它是不同的 - 它只是指最终的子区间,并具有不同的含义)

+0

你怎么看待:'findInterval(X,C(-Inf,头(VEC,-1)))'? – sgibb

+0

@sgibb似乎并没有做到这一点,我添加了一个例子,你的结果并不一样。 –

+0

我在这里有点困惑,但'findInterval(x-1,vec)'做你正在寻找什么? – thelatemail

回答

10

编辑:专业全部清理过道。您可能会看到cut。默认情况下,cut使左开放和右闭合间隔,并可以使用适当的参数(right)进行更改。要使用你的例子:

x <- c(3, 6, 7, 7, 29, 37, 52) 
vec <- c(2, 5, 6, 35) 
cutVec <- c(vec, max(x)) # for cut, range of vec should cover all of x 

现在创建四个功能应该做同样的事情:二是从OP,一个来自乔希·奥布莱恩,然后cutcut的两个参数已从默认设置更改为:include.lowest = TRUE将为最小(最左边)的间隔创建两侧关闭的间隔。 labels = FALSE将导致cut简单地返回垃圾箱的整数值,而不是创建一个因子,否则它会这样做。

findInterval.rightClosed <- function(x, vec, ...) { 
    fi <- findInterval(x, vec, ...) 
    fi - (x==vec[fi]) 
} 
findInterval.rightClosed2 <- function(x, vec, ...) { 
    length(vec) - findInterval(-x, -rev(vec), ...) 
} 
cutFun <- function(x, vec){ 
    cut(x, vec, include.lowest = TRUE, labels = FALSE) 
} 
# The body of fiFun is a contribution by Josh O'Brien that got fed to the ether. 
fiFun <- function(x, vec){ 
    xxFI <- findInterval(x, vec * (1 + .Machine$double.eps)) 
} 

所有函数都返回相同的结果吗?对。 (注意对于cutFun使用cutVec

mapply(identical, list(findInterval.rightClosed(x, vec)), 
    list(findInterval.rightClosed2(x, vec), cutFun(x, cutVec), fiFun(x, vec))) 
# [1] TRUE TRUE TRUE 

现在更苛刻的载体斌:

x <- rpois(2e6, 10) 
vec <- c(-Inf, quantile(x, seq(.2, 1, .2))) 

测试相同(注意使用unname

mapply(identical, list(unname(findInterval.rightClosed(x, vec))), 
    list(findInterval.rightClosed2(x, vec), cutFun(x, vec), fiFun(x, vec))) 
# [1] TRUE TRUE TRUE 

和Benchmark是否:

library(microbenchmark) 
microbenchmark(findInterval.rightClosed(x, vec), findInterval.rightClosed2(x, vec), 
    cutFun(x, vec), fiFun(x, vec), times = 50) 
# Unit: milliseconds 
#        expr  min  lq median  uq  max 
# 1     cutFun(x, vec) 35.46261 35.63435 35.81233 36.68036 53.52078 
# 2      fiFun(x, vec) 51.30158 51.69391 52.24277 53.69253 67.09433 
# 3 findInterval.rightClosed(x, vec) 124.57110 133.99315 142.06567 155.68592 176.43291 
# 4 findInterval.rightClosed2(x, vec) 79.81685 82.01025 86.20182 95.65368 108.51624 

从这次跑步看,cut似乎是最快的。

+0

谢谢。我似乎记得'cut'效率较低,并且它也不允许像'findInterval'那样追踪'vec'的右边缘(请参阅输出中的第15-17行),但该部分可以工作在最后加入一个'Inf'。 –

+0

@KenWilliams,是的,用'breaks'覆盖'x'的整个范围可以让你切掉所有的'x'(参见我的编辑)。至于效率,那么代码至少已经存在了。 – BenBarnes

+0

@KenWilliams,如果你计算效率基准的速度,毕竟'findInterval'和'cut'之间可能没有太大的区别。 “cut”的减速可能通常来自转换为因素和制作标签? – BenBarnes

-1

如果你的限制是间隔,你可以增加正确的间隔一点点:interval + c(0,0.1)会做:findinterval(value,interval + c(0,0。1))

+0

这不会出于各种原因。最根本的是,回收利用会导致这种情况改变每个奇数条目的正确间隔,而不是全部。此外,这假设您知道数据的离散化宽于0.1。 –

1

也许你可以使用left.open选项:

findInterval(x, vec, left.open=T) 
[1] 1 2 3 3 3 4 4 
+0

是的 - 此选项已添加到2016年10月发布的R版本3.3.2中。现在是正确的方法。 –

相关问题