通过比较R中的两个数据帧找到最近点
Finding closest point by comparing two data frames in R
我在 R 中有一组两个数据帧
First:
site_no <- c("02110500","02110550", "02110701" , "02110704", "02110760", "02110777", "021108044", "02110815")
lat_coor <- c(33.91267, 33.85083, 33.86100, 33.83295, 33.74073, 33.85156, 33.65017, 33.44461)
long_coor <- c(-78.71502, -78.89722, -79.04115, -79.04365, -78.86669, -78.65585, -79.12310, -79.17393)
AllStations <- data.frame(site_no, lat_coor, long_coor)
Second:
station <- c("USGS-02146110","USGS-02146110","USGS-02146110","USGS-02146110","USGS-02146110","USGS-021473426","USGS-021473426","USGS-021473426")
latitude <- c(34.88928, 34.85651, 34.85651, 34.85651, 34.71679, 34.24320, 34.80012, 34.80012)
longitude <- c(-81.06869, -82.22622, -82.22622, -82.22622, -82.17372, -81.31954, -82.36512, -82.36512)
ContaminantStations <- data.frame(station, latitude, longitude)
我的数据集要长很多,但为了这个问题的目的,我认为这应该足够了。
我想要的是从第一个数据框 (AllStations) 中找到所有位于第二个数据框 (ContaminantStations) 中的点的半径内的站,并将它们附加到一个新的数据框(仅来自 AllStations 的那些),我需要提取该站及其所有信息。我尝试了一些合乎逻辑的方法,但其中 none 有效或有意义。我也尝试使用 RANN:nn2 但这只会给我计数。
如有任何帮助,我们将不胜感激
我认为您只需要遍历 AllStations
和 return 中距离最近的 ContaminantStations
半径内的每个。
func <- function(stations, constations, radius = 250000) {
if (!NROW(stations) || !NROW(constations)) return()
if (length(radius) == 1 && NROW(constations) > 1) {
radius <- rep(radius, NROW(constations))
} else if (length(radius) != NROW(constations)) {
stop("'radius' must be length 1 or the same as the number of rows in 'constations'")
}
out <- integer(NROW(stations))
for (i in seq_len(NROW(stations))) {
dists <- geosphere::distHaversine(stations[i,], constations)
out[i] <- if (any(dists <= radius)) which.min(dists) else 0L
}
return(out)
}
这return是一个整数向量,表示最近的污染站。如果 none 在半径内,则它 returns 0
。这可以安全地用作原始框架上的 row-index。
每个参数只能包含两列,第一列是经度。 (我不假设函数中的列名。)radius
以米为单位,与 geosphere
包假设一致。
ind <- func(AllStations[,c("long_coor", "lat_coor")], ContaminantStations[,c("longitude", "latitude")],
radius = 230000)
ind
# [1] 0 6 6 6 0 0 6 6
这些是 ContaminantStations
行的索引,其中 non-zero 表示该污染站最接近 AllStations
的特定行。
我们可以确定哪个污染站离这个最近(有很多方法可以做到这一点,包括 tidyverse 和其他技术……这只是一个开始)。
AllStations$ClosestContaminantStation <- NA_character_
AllStations$ClosestContaminantStation[ind > 0] <- ContaminantStations$station[ind]
AllStations
# site_no lat_coor long_coor ClosestContaminantStation
# 1 02110500 33.91267 -78.71502 <NA>
# 2 02110550 33.85083 -78.89722 USGS-021473426
# 3 02110701 33.86100 -79.04115 USGS-021473426
# 4 02110704 33.83295 -79.04365 USGS-021473426
# 5 02110760 33.74073 -78.86669 <NA>
# 6 02110777 33.85156 -78.65585 <NA>
# 7 021108044 33.65017 -79.12310 USGS-021473426
# 8 02110815 33.44461 -79.17393 USGS-021473426
透视您的数据:
此方法的替代方法是 return 最近污染站的距离和索引,无论半径如何,允许您稍后过滤。
func2 <- function(stations, constations, radius = 250000) {
if (!NROW(stations) || !NROW(constations)) return()
if (length(radius) == 1 && NROW(constations) > 1) {
radius <- rep(radius, NROW(constations))
} else if (length(radius) != NROW(constations)) {
stop("'radius' must be length 1 or the same as the number of rows in 'constations'")
}
out <- data.frame(ind = integer(NROW(stations)), dist = numeric(NROW(stations)))
for (i in seq_len(NROW(stations))) {
dists <- geosphere::distHaversine(stations[i,], constations)
out$ind[i] <- which.min(dists)
out$dist[i] <- min(dists)
}
return(out)
}
演示,包括将污染站纳入同一框架。
AllStations2 <- cbind(
AllStations,
func2(AllStations[,c("long_coor", "lat_coor")], ContaminantStations[,c("longitude", "latitude")])
)
AllStations2
# site_no lat_coor long_coor ind dist
# 1 02110500 33.91267 -78.71502 1 241971.5
# 2 02110550 33.85083 -78.89722 6 227650.6
# 3 02110701 33.86100 -79.04115 6 214397.8
# 4 02110704 33.83295 -79.04365 6 214847.7
# 5 02110760 33.74073 -78.86669 6 233190.8
# 6 02110777 33.85156 -78.65585 6 249519.7
# 7 021108044 33.65017 -79.12310 6 213299.3
# 8 02110815 33.44461 -79.17393 6 217378.9
AllStations3 <- cbind(
AllStations2,
ContaminantStations[AllStations2$ind,]
)
AllStations3
# site_no lat_coor long_coor ind dist station latitude longitude
# 1 02110500 33.91267 -78.71502 1 241971.5 USGS-02146110 34.88928 -81.06869
# 6 02110550 33.85083 -78.89722 6 227650.6 USGS-021473426 34.24320 -81.31954
# 6.1 02110701 33.86100 -79.04115 6 214397.8 USGS-021473426 34.24320 -81.31954
# 6.2 02110704 33.83295 -79.04365 6 214847.7 USGS-021473426 34.24320 -81.31954
# 6.3 02110760 33.74073 -78.86669 6 233190.8 USGS-021473426 34.24320 -81.31954
# 6.4 02110777 33.85156 -78.65585 6 249519.7 USGS-021473426 34.24320 -81.31954
# 6.5 021108044 33.65017 -79.12310 6 213299.3 USGS-021473426 34.24320 -81.31954
# 6.6 02110815 33.44461 -79.17393 6 217378.9 USGS-021473426 34.24320 -81.31954
在这里,您可以随意选择半径:
subset(AllStations3, dist < 230000)
# site_no lat_coor long_coor ind dist station latitude longitude
# 6 02110550 33.85083 -78.89722 6 227650.6 USGS-021473426 34.2432 -81.31954
# 6.1 02110701 33.86100 -79.04115 6 214397.8 USGS-021473426 34.2432 -81.31954
# 6.2 02110704 33.83295 -79.04365 6 214847.7 USGS-021473426 34.2432 -81.31954
# 6.5 021108044 33.65017 -79.12310 6 213299.3 USGS-021473426 34.2432 -81.31954
# 6.6 02110815 33.44461 -79.17393 6 217378.9 USGS-021473426 34.2432 -81.31954
我在 R 中有一组两个数据帧
First:
site_no <- c("02110500","02110550", "02110701" , "02110704", "02110760", "02110777", "021108044", "02110815")
lat_coor <- c(33.91267, 33.85083, 33.86100, 33.83295, 33.74073, 33.85156, 33.65017, 33.44461)
long_coor <- c(-78.71502, -78.89722, -79.04115, -79.04365, -78.86669, -78.65585, -79.12310, -79.17393)
AllStations <- data.frame(site_no, lat_coor, long_coor)
Second:
station <- c("USGS-02146110","USGS-02146110","USGS-02146110","USGS-02146110","USGS-02146110","USGS-021473426","USGS-021473426","USGS-021473426")
latitude <- c(34.88928, 34.85651, 34.85651, 34.85651, 34.71679, 34.24320, 34.80012, 34.80012)
longitude <- c(-81.06869, -82.22622, -82.22622, -82.22622, -82.17372, -81.31954, -82.36512, -82.36512)
ContaminantStations <- data.frame(station, latitude, longitude)
我的数据集要长很多,但为了这个问题的目的,我认为这应该足够了。
我想要的是从第一个数据框 (AllStations) 中找到所有位于第二个数据框 (ContaminantStations) 中的点的半径内的站,并将它们附加到一个新的数据框(仅来自 AllStations 的那些),我需要提取该站及其所有信息。我尝试了一些合乎逻辑的方法,但其中 none 有效或有意义。我也尝试使用 RANN:nn2 但这只会给我计数。
如有任何帮助,我们将不胜感激
我认为您只需要遍历 AllStations
和 return 中距离最近的 ContaminantStations
半径内的每个。
func <- function(stations, constations, radius = 250000) {
if (!NROW(stations) || !NROW(constations)) return()
if (length(radius) == 1 && NROW(constations) > 1) {
radius <- rep(radius, NROW(constations))
} else if (length(radius) != NROW(constations)) {
stop("'radius' must be length 1 or the same as the number of rows in 'constations'")
}
out <- integer(NROW(stations))
for (i in seq_len(NROW(stations))) {
dists <- geosphere::distHaversine(stations[i,], constations)
out[i] <- if (any(dists <= radius)) which.min(dists) else 0L
}
return(out)
}
这return是一个整数向量,表示最近的污染站。如果 none 在半径内,则它 returns 0
。这可以安全地用作原始框架上的 row-index。
每个参数只能包含两列,第一列是经度。 (我不假设函数中的列名。)radius
以米为单位,与 geosphere
包假设一致。
ind <- func(AllStations[,c("long_coor", "lat_coor")], ContaminantStations[,c("longitude", "latitude")],
radius = 230000)
ind
# [1] 0 6 6 6 0 0 6 6
这些是 ContaminantStations
行的索引,其中 non-zero 表示该污染站最接近 AllStations
的特定行。
我们可以确定哪个污染站离这个最近(有很多方法可以做到这一点,包括 tidyverse 和其他技术……这只是一个开始)。
AllStations$ClosestContaminantStation <- NA_character_
AllStations$ClosestContaminantStation[ind > 0] <- ContaminantStations$station[ind]
AllStations
# site_no lat_coor long_coor ClosestContaminantStation
# 1 02110500 33.91267 -78.71502 <NA>
# 2 02110550 33.85083 -78.89722 USGS-021473426
# 3 02110701 33.86100 -79.04115 USGS-021473426
# 4 02110704 33.83295 -79.04365 USGS-021473426
# 5 02110760 33.74073 -78.86669 <NA>
# 6 02110777 33.85156 -78.65585 <NA>
# 7 021108044 33.65017 -79.12310 USGS-021473426
# 8 02110815 33.44461 -79.17393 USGS-021473426
透视您的数据:
此方法的替代方法是 return 最近污染站的距离和索引,无论半径如何,允许您稍后过滤。
func2 <- function(stations, constations, radius = 250000) {
if (!NROW(stations) || !NROW(constations)) return()
if (length(radius) == 1 && NROW(constations) > 1) {
radius <- rep(radius, NROW(constations))
} else if (length(radius) != NROW(constations)) {
stop("'radius' must be length 1 or the same as the number of rows in 'constations'")
}
out <- data.frame(ind = integer(NROW(stations)), dist = numeric(NROW(stations)))
for (i in seq_len(NROW(stations))) {
dists <- geosphere::distHaversine(stations[i,], constations)
out$ind[i] <- which.min(dists)
out$dist[i] <- min(dists)
}
return(out)
}
演示,包括将污染站纳入同一框架。
AllStations2 <- cbind(
AllStations,
func2(AllStations[,c("long_coor", "lat_coor")], ContaminantStations[,c("longitude", "latitude")])
)
AllStations2
# site_no lat_coor long_coor ind dist
# 1 02110500 33.91267 -78.71502 1 241971.5
# 2 02110550 33.85083 -78.89722 6 227650.6
# 3 02110701 33.86100 -79.04115 6 214397.8
# 4 02110704 33.83295 -79.04365 6 214847.7
# 5 02110760 33.74073 -78.86669 6 233190.8
# 6 02110777 33.85156 -78.65585 6 249519.7
# 7 021108044 33.65017 -79.12310 6 213299.3
# 8 02110815 33.44461 -79.17393 6 217378.9
AllStations3 <- cbind(
AllStations2,
ContaminantStations[AllStations2$ind,]
)
AllStations3
# site_no lat_coor long_coor ind dist station latitude longitude
# 1 02110500 33.91267 -78.71502 1 241971.5 USGS-02146110 34.88928 -81.06869
# 6 02110550 33.85083 -78.89722 6 227650.6 USGS-021473426 34.24320 -81.31954
# 6.1 02110701 33.86100 -79.04115 6 214397.8 USGS-021473426 34.24320 -81.31954
# 6.2 02110704 33.83295 -79.04365 6 214847.7 USGS-021473426 34.24320 -81.31954
# 6.3 02110760 33.74073 -78.86669 6 233190.8 USGS-021473426 34.24320 -81.31954
# 6.4 02110777 33.85156 -78.65585 6 249519.7 USGS-021473426 34.24320 -81.31954
# 6.5 021108044 33.65017 -79.12310 6 213299.3 USGS-021473426 34.24320 -81.31954
# 6.6 02110815 33.44461 -79.17393 6 217378.9 USGS-021473426 34.24320 -81.31954
在这里,您可以随意选择半径:
subset(AllStations3, dist < 230000)
# site_no lat_coor long_coor ind dist station latitude longitude
# 6 02110550 33.85083 -78.89722 6 227650.6 USGS-021473426 34.2432 -81.31954
# 6.1 02110701 33.86100 -79.04115 6 214397.8 USGS-021473426 34.2432 -81.31954
# 6.2 02110704 33.83295 -79.04365 6 214847.7 USGS-021473426 34.2432 -81.31954
# 6.5 021108044 33.65017 -79.12310 6 213299.3 USGS-021473426 34.2432 -81.31954
# 6.6 02110815 33.44461 -79.17393 6 217378.9 USGS-021473426 34.2432 -81.31954