1) Rfast Используя dista
в Rfast, мы получаем индексы ближайших двух. Возьмите второе самое близкое, так как самое близкое будет то же самое значение.
library(Rfast)
x <- c(4, 14, 11, 3, 16) # input
x[ dista(x, x, k = 2, index = TRUE)[, 2] ]
## [1] 3 16 14 4 14
2) sqldf Используя SQL, мы можем левее присоединить DF к себе, исключая то же самое значение значения, и взять строка с минимальным расстоянием.
DF <- data.frame(x) # x is from (1)
sqldf("select a.x, b.x nearest, min(abs(a.x - b.x))
from DF a
left join DF b on a.x != b.x
group by a.rowid")[1:2]
, дающая:
x nearest
1 4 3
2 14 16
3 11 14
4 3 4
5 16 14
3) zoo Отсортируйте входные данные, примите значение, соответствующее наименьшей разнице на любом из сторона каждого элемента и заказать его обратно.
library(zoo)
ix <- order(x)
least <- function(x) if (x[2] - x[1] < x[3] - x[2]) x[1] else x[3]
rollapply(c(-Inf, x[ix], Inf), 3, least)[order(ix)]
## [1] 3 16 14 4 14
4) База R Используя ix
и least
из (3), мы можем имитировать c (3) используя только базовые функции следующим образом.
apply(embed(c(-Inf, x[ix], Inf), 3)[, 3:1], 1, least)[order(ix)]
## [1] 3 16 14 4 14
4a) Этот немного более короткий вариант также будет работать:
-apply(embed(-c(-Inf, x[ix], Inf), 3), 1, least)[order(ix)]
## [1] 3 16 14 4 14
4b) Упрощение в дальнейшем у нас есть следующее базовое решение, где, опять же, ix
от (3):
xx <- x[ix]
x1 <- c(-Inf, xx[-length(xx)])
x2 <- c(xx[-1], Inf)
ifelse(xx - x1 < x2 - xx, x1, x2)[order(ix)]
## [1] 3 16 14 4 14
Дубликаты
В примере в вопросе не было дубликатов, но если были дубликаты, есть некоторый вопрос относительно определения проблемы. Например, если у нас было c(1, 3, 4, 1)
, то, если мы посмотрим на первое значение, 1, есть другое значение, точно равное ему, поэтому самое близкое значение равно 1. Другая интерпретация состоит в том, что должно быть возвращено самое близкое значение, не равное 1, которое в этот случай равен 3. В приведенных выше кодах решение sqldf
дает самое близкое значение, не равное текущему значению, тогда как другие дают самое близкое значение среди оставшихся значений.
Если мы хотели интерпретацию самого близкого не равный для тех, кто отличается от sqldf
, тогда мы могли бы использовать rle
после заказа, чтобы сжать его до уникальных значений, а затем использовать inverse.rle
впоследствии, как показано на измененном 4b:
x <- c(1, 3, 4, 1)
ix <- order(x)
r <- rle(x[ix])
xx <- r$values
x1 <- c(-Inf, xx[-length(xx)])
x2 <- c(xx[-1], Inf)
r$values <- ifelse(xx - x1 < x2 - xx, x1, x2)
inverse.rle(r)[order(ix)]
## [1] 3 4 3 3