我有一个data.table
,带有957个地理编码。我想将其与另一个具有317个地理编码的数据集进行匹配。匹配条件是地理空间接近度。我想将第一个数据集中的每个观测值与第二个数据集中的一个观测值匹配,以使两个观测值之间的距离等于或小于5000米。
我的数据如下:
> muni[1:3]
mun Lat_Decimal Lon_Decimal
1: 1001 21.76672 -102.2818
2: 1002 22.16597 -102.0657
3: 1003 21.86138 -102.7248
> stations[1:3]
station_number station_lat station_long
1: 10003 25.100 -106.567
2: 10018 24.944 -106.259
3: 10031 24.523 -105.952
我正在使用distm
中的library(geosphere)
函数来计算距离。
我认为解决此问题的方法是while
循环。这个想法是从muni
中获取第一个观测值,并在stations
中测量到第一个观测值的距离。如果距离等于或小于5000米,则将station_number
中第一个观测值的station
分配给muni
中的第一个观测值。如果距离大于5000,请尝试在muni
中进行下一个观察,直到距离等于或小于5000米。
从本质上讲,这是一个循环,可找到stations
中的第一个观测点,该观测点距muni
中的观测点5000米或更近。
这是初步尝试:
for (i in 1:957) {
j = 1
while (distm(muni[i, .(Lon_Decimal, Lat_Decimal)],
stations[j, .(station_long, station_lat)]) > 5000 & j <= 317) {
muni[i, station_number := as.integer(stations[j, station_number])]
muni[i, distance := distm(muni[i, .(Lon_Decimal, Lat_Decimal)],
stations[j, .(station_long, station_lat)])]
j = j + 1
}
}
我可以说这是行不通的,因为运行此循环for (i in 1:3)
后,'muni'中的所有行似乎都没有被覆盖。我想我的循环中有一个错误,忽略了station_number :=
和distance :=
部分。
我希望此循环会覆盖muni
,以使整个列都具有一个station_number
。
答案 0 :(得分:1)
我已将您的几个示例点读为data.frames
,并将其转换为下面的sf
以获取答案。如果您依附于geosphere
,请原谅双关语,因为geosphere::distm
还会返回距离矩阵。
首先,我们将您的数据转换为sf
格式:
library(sf)
stations_raw <- "station_number station_lat station_long
1: 10003 25.100 -106.567
2: 10018 24.944 -106.259
3: 10031 24.523 -105.952"
mun_raw <- "mun Lat_Decimal Lon_Decimal
1: 1001 21.76672 -102.2818
2: 1002 22.16597 -102.0657
3: 1003 21.86138 -102.7248"
mun_df <- read.table(text = mun_raw)
stations_df <- read.table(text = stations_raw)
mun_sf <- st_as_sf(mun_df, coords = c("Lon_Decimal", "Lat_Decimal"), crs = 4326)
stations_sf <- st_as_sf(stations_df,
coords = c("station_long", "station_lat"), crs = 4326)
然后,找到点之间每次交互的最小值:
closest <- list()
for(i in seq_len(nrow(mun_sf))){
closest[[i]] <- stations_sf[which.min(
st_distance(stations_sf, mun_sf[i,])),]
}
最后,我们提取标识符并将其附加到原始df,并根据您的要求删除mun_id:
mun_sf$closest_station <- purrr::map_chr(closest, "station_number")
mun_sf <- mun_sf[, c("closest_station", "geometry")]
mun_sf
#> Simple feature collection with 3 features and 1 field
#> geometry type: POINT
#> dimension: XY
#> bbox: xmin: -102.7248 ymin: 21.76672 xmax: -102.0657 ymax: 22.16597
#> epsg (SRID): 4326
#> proj4string: +proj=longlat +datum=WGS84 +no_defs
#> closest_station geometry
#> 1: 10031 POINT (-102.2818 21.76672)
#> 2: 10031 POINT (-102.0657 22.16597)
#> 3: 10031 POINT (-102.7248 21.86138)
下面的图表有助于直观地检查这个玩具示例中的答案是否正确。
ggplot() +
geom_sf(data = mun_sf, colour = "red") +
geom_sf_text(data = mun_sf, aes(label = mun), nudge_x = 0.25) +
geom_sf(data = stations_sf, colour = "blue") +
geom_sf_text(data = stations_sf, aes(label = station_number), nudge_x = -0.25)
#> Warning in st_point_on_surface.sfc(sf::st_zm(x)): st_point_on_surface may
#> not give correct results for longitude/latitude data
#> Warning in st_point_on_surface.sfc(sf::st_zm(x)): st_point_on_surface may
#> not give correct results for longitude/latitude data