[英]Map locations to their nearest location based on latitude and longitude
我有兩組位置,分別是A(2萬個位置)和B(2k個位置)。 我想根據位置的經度和緯度,將A組中所有位置都映射到B組中最接近的位置。
有Java或R中的任何解決方案嗎?首選Java解決方案。
從@rosscova的答案
拿點,但作為矩陣
pointsA <- as.matrix(data.frame( lat = c( 10, 12, 20 ), lon = c( 12, 17, 10 ) ))
pointsB <- as.matrix(data.frame( lat = c( 11, 15 ), lon = c( 15, 15 ) ))
然后,在處理坐標時,您可能更喜歡使用大圓(WGS84橢球)距離而不是歐幾里得距離。 我通常使用sp包中的spDists函數
library( sp )
out_Dists <- spDists(x = pointsA, y = pointsB, longlat = TRUE, segments = FALSE, diagonal = FALSE)
在使用與which.min超過行的應用功能以最終獲得最近pointB以點A
pointsA[ apply(out_Dists, 1, which.min), ]
我@STaefi同意的意見,這是一個好主意,要求別人寫的代碼在你面前表現出至少您的部分工作一點點 。 話雖如此,您的問題引起了我的興趣,足以吸引我幾分鍾的時間,因此這是R
的一種方法。 請注意,盡管這只是將距離視為坐標的sqrt(a^2+b^2)
函數,但除赤道外其他任何地方都不准確。 如果需要更高的准確性,則需要對其進行修改。
取一個小的假設數據集:
pointsA <- data.frame( lat = c( 10, 12, 20 ), lon = c( 12, 17, 10 ) )
pointsB <- data.frame( lat = c( 11, 15 ), lon = c( 15, 15 ) )
編寫一個用於計算最接近點的函數:
closest_point <- function( lat1, lon1, lat2, lon2 ) {
x_dist <- abs( lon1 - lon2 )
y_dist <- abs( lat1 - lat2 )
dist <- sqrt( x_dist ^ 2 + y_dist ^ 2 )
closest <- data.frame( lat = lat2[ which.min( dist ) ],
lon = lon2[ which.min( dist ) ] )
return( closest )
}
我們可以從一個點執行該功能pointsA
,返回從最近點pointsB
:
closest_point( pointsA[1,"lat"], pointsA[1,"lon"], pointsB[,"lat"], pointsB[,"lon"] )
# lat lon
# 1 11 15
或者,我們可以將其應用到從所有點pointsA
,返回從最近點pointsB
對每個點的pointsA
closest.points <- lapply( seq_len( nrow( pointsA ) ),
function(x) {
closest_point( lat1 = pointsA[x,"lat"],
lon1 = pointsA[x,"lon"],
lat2 = pointsB[,"lat"],
lon2 = pointsB[,"lon"] )
} )
closest.points <- do.call( rbind, closest.points )
closest.points
# lat lon
# 1 11 15
# 2 11 15
# 3 15 15
這是Java中的一個。 通過將緯度和經度轉換為歸一化的向量表示形式,簡化了數學運算,並注意到兩個向量越接近,其點積就越大(當它們相等時,接近一個)。
假設地球是球形的。 如果要獲得“完美”的結果,則需要使用更接近的近似值(例如WGS84)轉換坐標。
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static java.lang.Math.*;
public class LatLong {
public static void main(String[] args) throws Exception {
// A random lat/long
double[] target = randLatLong();
// Transform to ECEF vector
double[] targetv = toEcef(target);
// 2000 random candidates
List<double[]> b = Stream.generate(LatLong::randLatLong).limit(2000).collect(Collectors.toList());
// Transform candidates to ECEF representation
List<double[]> bv = b.stream().map(LatLong::toEcef).collect(Collectors.toList());
// Find the closest candidate to the target
int i = closest(targetv, bv);
System.out.println("Closest point to " + target[0] + ", " + target[1] + " is " + b.get(i)[0] + ", " + b.get(i)[1]);
}
// index of closest vector to target from list of candidates
public static int closest(double[] target, List<double[]> candidates) {
double p = Double.MIN_VALUE;
int closest = -1;
for (int i = 0; i < candidates.size(); i++) {
double next = dotProduct(target, candidates.get(i));
if (next > p) {
p = next;
closest = i;
}
}
return closest;
}
// dot product of two 3vectors
public static double dotProduct(double[] v1, double[] v2) {
return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2];
}
// lat/long in degrees to normalised ECEF vector
public static double[] toEcef(double[] latLong) {
return toEcef(toRadians(latLong[0]), toRadians(latLong[1]));
}
// lat/long in radians to normalised ECEF vector
public static double[] toEcef(double φ, double λ) {
return new double[] {cos(φ) * cos(λ), cos(φ) * sin(λ), sin(φ)};
}
// A random lat/long
public static double[] randLatLong() {
return new double[] {Math.random() * 180 - 90, Math.random() * 360 - 180};
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.