【问题标题】:While loop inside a for loop to calculate geospatial distance between 2 datasets in R在for循环中循环以计算R中2个数据集之间的地理空间距离
【发布时间】:2019-02-11 05:00:16
【问题描述】:

我有一个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

我正在使用library(geosphere) 中的distm 函数来计算距离。

我认为解决这个问题的方法是while 循环。这个想法是从muni 中获取第一个观测值,并测量到stations 中的第一个观测值的距离。如果距离为 5000 米或更短,则将station 中的第一个观测值的station_number 分配给muni 中的第一个观测值。如果距离大于5000,则在muni尝试下一次观察,直到距离在5000米以内。

本质上,这是一个循环,它会在 stations 中找到第一个观测值,即 5000 米或更接近 muni 中的观测值。

这是一个初步的尝试:

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

【问题讨论】:

  • 如果您可以将每个muni 观测值与其最近的station 进行匹配,而不是从station 数据集中的5000 米以下的第一个观测值匹配,您会满意吗?
  • 您能否提供我们可以使用的数据集?
  • @FonsMA 我认为用

标签: r gis sf geosphere


【解决方案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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-06-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多