2014-09-24 13 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

+0

ну, я думаю, вы можете так выразиться – Wicelo

+0

Мое предположение заключается в том, что функция соединения 'data.table'' roll = "ближайшее" 'будет полезна здесь, ала http://stackoverflow.com/questions/15712826/ join-r-data-tables-where-key-values-are-not-just-equal-comb-rows-with-clo – Chase

ответ

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

+0

@Wicelo Это тривиально, чтобы перевести на Rcpp. – Roland

1

Я считаю, что это лучшее, что вы можете получить: sum(abs(sort(a) - sort(b)))

Я использую data.table сохранить первоначальную сортировку a:

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))] 

Это решение дает лучший результат, если сравнивать к решению Чейза:

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

+0

ну, мне очень понравилось решение nicola, но вы правы, ваше решение дает лучшую разницу. 'придется изучать 'данные.format', а также 'setkey' и': = 'оператор, я не знал этих вещей ** edit **: ну, на самом деле, решение Джеймса дает ту же самую сумму разницы и является на liner – Wicelo

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

+0

См. '?" << - "' для значения '' и '<< -' операторов. «<< -» опасен, поскольку он меняет объект за пределы функции. – nicola

Смежные вопросы