Нахождение ближайшего соседа между 2 наборами датированных точек - PullRequest
1 голос
/ 14 декабря 2011

У меня есть 2 набора точек, set1 и set2. Оба набора точек имеют данные, связанные с этой точкой. Точки в наборе 1 являются «эфемерными» и существуют только на указанную дату. Точки в наборе 2 являются «постоянными», создаются на определенную дату, а затем существуют навсегда после этой даты.

set.seed(1)
dates <- seq(as.Date('2011-01-01'),as.Date('2011-12-31'),by='days')

set1 <- data.frame(lat=40+runif(10000),
lon=-70+runif(10000),date=sample(dates,10000,replace=TRUE))

set2 <- data.frame(lat=40+runif(100),
lon=-70+runif(100),date=sample(dates,100,replace=TRUE))

Вот моя проблема: для каждой точки в set1 (эфемерной) найдите расстояние до ближайшей точки в set2 (постоянной), которая была построена ДО того, как событие set1 произошло. Например, 1-я точка в set1 произошла 2011-03-18:

> set1[1,]
       lat       lon       date
1 40.26551 -69.93529 2011-03-18

Итак, я хочу найти ближайшую точку в set2, которая была построена до 2011-03-18:

> head(set2[set2$date<=as.Date('2011-04-08'),])
        lat       lon       date
1  40.41531 -69.25765 2011-02-18
7  40.24690 -69.29812 2011-02-19
13 40.10250 -69.52515 2011-02-12
14 40.53675 -69.28134 2011-02-27
17 40.66236 -69.07396 2011-02-17
20 40.67351 -69.88217 2011-01-04

Дополнительная складка в том, что это точки широты / долготы, поэтому я должен рассчитать расстояния вдоль поверхности земли. Пакет R поля предоставляет удобную функцию для этого:

require(fields)
distMatrix <- rdist.earth(set1[,c('lon','lat')], 
set2[,c('lon','lat')], miles = TRUE)

Мой вопрос: как я могу отрегулировать расстояния в этой матрице до Inf, если точка в set2 (столбец матрицы расстояний) была построена после точки в set1 (матрица строк расстояний)?

Ответы [ 2 ]

3 голосов
/ 14 декабря 2011

Вот что я бы сделал:

earlierMatrix <- outer(set1$date, set2$date, "<=")
distMatrix2 <- distMatrix + ifelse(earlierMatrix, Inf, 0)
0 голосов
/ 14 декабря 2011

Вот моя попытка ответа. Это не особенно эффективно, но я думаю, что это правильно. Это также позволяет легко использовать различные калькуляторы расстояния:

#Calculate distances 
require(fields)
distMatrix <- lapply(1:nrow(set1),function(x) {

    #Find distances to all points
    distances <- rdist.earth(set1[x,c('lon','lat')], set2[,c('lon','lat')], miles = TRUE)

    #Set distance to Inf if the set1 point occured BEFORE the set2 dates
    distances <- ifelse(set1[x,'date']<set2[,'date'], Inf, distances)

    return(distances)
})
distMatrix  <- do.call(rbind,distMatrix)

#Find distance to closest object
set1$dist <- apply(distMatrix,1,min)

#Find id of closest object
objectID <- lapply(1:nrow(set1),function(x) {
    if (set1[x,'dist']<Inf) {
        IDs <- which(set1[x,'dist']==distMatrix[x,])
    } else {
        IDs <- NA
    }
    return(sample(IDs,1)) #Randomly break ties (if there are any)
})
set1$objectID <- do.call(rbind,objectID)

Вот заголовок результирующего набора данных:

> head(set1)
       lat       lon       date      dist objectID
1 40.26551 -69.93529 2011-03-18  3.215514       13
2 40.37212 -69.32339 2011-02-11 10.320910       46
3 40.57285 -69.26463 2011-02-23  3.954132        4
4 40.90821 -69.88870 2011-04-24  4.132536       49
5 40.20168 -69.95335 2011-02-24  4.284692       45
6 40.89839 -69.86909 2011-07-12  3.385769       57
...