2014-09-24 101 views
4

我得到这个代码,创建两个向量和从a每个元素我想在b最接近的元素:如何获得另一个向量中每个元素的向量中最接近的元素而不重复?

a = rnorm(100) 
b = rnorm(100) 
c = vapply(a, function(x) which.min(abs(b - x)), 1) 
table(duplicated(c)) 

FALSE TRUE 
    61 39 

正如你可以看到这个方法是及时给予了很多重复的这是正常的但我想不要有重复。一旦索引被选中,我想从b删除发生,但我不知道如何在vapply下完成。

+0

所以要清楚,你寻找一个排列,'p',使'sum(abs(ab [p]))'最小化? – James 2014-09-24 10:51:11

+0

以及我想你可以这样说 – Wicelo 2014-09-24 10:52:17

+0

我的猜测是'data.table'的连接函数'roll =“nearest”''在这里很有用,ala http://stackoverflow.com/questions/15712826/ join -r-data-tables-where-key-values-are-not-exactly-equal-combine-rows-with-clo – Chase 2014-09-24 10:52:19

回答

3

你会得到的最接近的匹配是通过排序向量,然后配对他们。 b下面的推测应该允许你这样做。

p <- order(b)[order(order(a))] # order on b and then back transform the ordering of a 

sum(abs(a-b[p])) 
[1] 20.76788 

显然,允许重复确实使事情更接近:

sum(abs(a-b[c])) 
[1] 2.45583 
0

这几乎可以肯定会在通过量化的改善,但似乎工作,可以完成这项工作:

set.seed(1) 
a = rnorm(5) 
b = rnorm(5) 

foo <- function(a,b) { 

    out <- cbind(a, bval = NA) 

    for (i in seq_along(a)) { 
    #which value of B is closest? 
    whichB <- which.min(abs(b - a[i])) 
    #Assign that value to the bval column 
    out[i, "bval"] <- b[whichB] 
    #Remove that value of B from being chosen again 
    b <- b[-whichB] 
    } 

    return(out) 

} 

#In action 
foo(a,b) 
--- 
       a  bval 
[1,] -0.6264538 -0.8204684 
[2,] 0.1836433 0.4874291 
[3,] -0.8356286 -0.3053884 
[4,] 1.5952808 0.7383247 
[5,] 0.3295078 0.5757814 
+0

你知道吗?如果矢量化解决方案是可能的? – Wicelo 2014-09-24 12:19:04

+0

@Wicelo这是微不足道的翻译成Rcpp。 – Roland 2014-09-24 12:31:03

1

我相信这是最好的,你可以得到:sum(abs(sort(a) - sort(b)))

我使用如果比较

require(data.table) 

set.seed(1) 

a <- rnorm(100) 
b <- rnorm(100) 

sum(abs(a - b)) 
sum(abs(sort(a) - sort(b))) 

dt <- data.table(a = a, b = b) 
dt[, id := .I] 

# sort dt by a 
setkey(dt, a) 

# sort b 
dt[, b := sort(b)] 

# return to original order 
setkey(dt, id) 

dt 
dt[, sum(abs(a - b))] 

该解决方案提供了更好的结果:data.table保存的a原来的排序大通的解决方案:

dt2 <- as.data.table(foo(a,b)) 
dt2[, sum(abs(a - bval))] 
dt[, sum(abs(a - b))] 

结果:

> dt2[, sum(abs(a - bval))] 
[1] 24.86731 
> dt[, sum(abs(a - b))] 
[1] 20.76788 
+1

良好的调用 - 通过'a'进行排序实际上更智能,会产生更好的结果。如果最初的顺序并不重要,那么只需'cbind(sort(a),sort(b)'是最直接的。 – Chase 2014-09-24 12:51:25

+0

我很喜欢nicola的解决方案,但是您的解决方案给出了更好的差异总和。必须研究这些数据。格式'以及'setkey'和':='运算符,我不知道这些事情**编辑**:事实上詹姆斯解决方案给出了相同的差额总和,是一个班轮 – Wicelo 2014-09-24 15:52:11

1

这是非常糟糕的编程,但可以工作,并且被矢量...

a <- rnorm(100) 
    b <- rnorm(100) 
    #make a copy of b (you'll see why) 
    b1<-b 
    res<- vapply(a, function(x) {ret<-which.min(abs(b1 - x));b1[ret]<<-NA;return(ret)}, 1) 
+0

很好,这正是什么我在发布前做过,但用'='而不是'<<'它没有工作,那两个操作员有什么区别?另外为什么你称之为糟糕的编程? – Wicelo 2014-09-24 13:57:42

+0

请参阅'?“<< - ”'以了解<-'和'<< - '运算符的含义。 '<< - '是危险的,因为它改变了函数范围之外的对象。 – nicola 2014-09-24 14:45:12