R - 在向量中找到最接近值的最快方法

时间:2017-04-18 06:16:39

标签: r

我有两个整数/ posixct向量:

a <- c(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15) #has > 2 mil elements
b <- c(4,6,10,16) # 200000 elements

现在我的结果向量c应该为向量的每个元素包含最近的b:

元素
c <- c(4,4,4,4,4,6,6,...)

我尝试使用apply和which.min(abs(a-b)),但它非常慢。

有没有更聪明的方法来解决这个问题?是否有data.table解决方案?

6 个答案:

答案 0 :(得分:4)

library(data.table)

a=data.table(Value=c(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15))

a[,merge:=Value]

b=data.table(Value=c(4,6,10,16))

b[,merge:=Value]

setkeyv(a,c('merge'))

setkeyv(b,c('merge'))

Merge_a_b=a[b,roll='nearest']

答案 1 :(得分:2)

不太确定它与您的音量有什么关系,但Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);非常快。

我们的想法是在cut的元素之间的中点处剪切矢量a

请注意,我假设b中的元素严格增加!

这样的事情:

b

使用像a <- c(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15) #has > 2 mil elements b <- c(4,6,10,16) # 200000 elements cuts <- c(-Inf, b[-1]-diff(b)/2, Inf) # Will yield: c(-Inf, 5, 8, 13, Inf) cut(a, breaks=cuts, labels=b) # [1] 4 4 4 4 4 6 6 6 10 10 10 10 10 16 16 # Levels: 4 6 10 16 这样的低级函数更快(这也是假设断点不递减)。

findInterval

当然,你可以这样做:

findInterval(a, cuts)
[1] 1 1 1 1 2 2 2 3 3 3 3 3 4 4 4

请注意,您可以通过将相关参数传递给index = findInterval(a, cuts) b[index] # [1] 4 4 4 4 6 6 6 10 10 10 10 10 16 16 16 (或a)来选择与b元素等距的cut元素会发生什么情况,请参阅他们的帮助页面。

答案 2 :(得分:1)

this link中所示,您可以执行以下操作:

which(abs(x-your.number)==min(abs(x-your.number)))

which.min(abs(x-your.number))

其中x是您的向量,your.number是值

答案 3 :(得分:1)

迟到了聚会,但是DescTools包中有一个名为Closest的函数,它几乎可以完全满足您的需要(它不会一次执行多个操作)

要解决此问题,我们可以在您的lapply列表上a,找到最接近的列表。

library(DescTools)

lapply(a, function(i) Closest(x = b, a = i))

您可能会注意到,返回的值多于a中的值。这是因为Closest将返回两个值,如果您要测试的值恰好在两个之间(例如3恰好在1和5之间,那么将同时返回1和5)。

要解决此问题,请将minmax放在结果周围:

lapply(a, function(i) min(Closest(x = b, a = i)))
lapply(a, function(i) max(Closest(x = b, a = i)))

然后unlist的结果得到纯矢量:)

答案 4 :(得分:1)

对于那些对慢速解决方案感到满意的人:

sapply(a, function(a, b) {b[which.min(abs(a-b))]}, b)

答案 5 :(得分:0)

使用max.col + outer,这可能是一个简单的基本R选项:

b[max.col(-abs(outer(a,b,"-")))]

给出

> b[max.col(-abs(outer(a,b,"-")))]
 [1]  4  4  4  4  6  6  6 10 10 10 10 10 16 16 16