2011-12-14 3 views
1

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

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 произошло. Например, первый пункт в 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 fields обеспечивает convienent function сделать это:

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

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

ответ

3

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

earlierMatrix <- outer(set1$date, set2$date, "<=") 
distMatrix2 <- distMatrix + ifelse(earlierMatrix, Inf, 0) 
+0

Очень элегантный. Спасибо! 1 небольшая ошибка: у вас есть оператор 'ifelse'. Если set1 $ date Zach

+0

Спасибо, и хороший улов. Должен быть очень осторожным, когда код начинает получать этот компакт! Другое решение сделать, хотите ли вы использовать '' <"' или '" <"' ... Я отредактировал его для '' <= "', так как это строго подразумевается в разделе «ПЕРЕД» в вашем вопросе ;) –

+0

Yup, это тоже работает. Спасибо за помощь! – Zach

0

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

#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 
Смежные вопросы