使用 nngeo 获取下一个邻居的 ID (nn_st)

Getting ID of next neigbour using nngeo (nn_st)

我需要计算物体(学校)之间的最近距离。我有两个 sf-data-frames(sf_special 和 sf_no_special)。我使用了 nngeo 包和 nn_st 命令,效果很好! nn_st 的输出是 a) 最近的两所学校之间的距离和 b) 最近学校的索引。最近学校的索引无法帮助我识别学校。我想要的是学号(id)。如何使用最近邻居的索引检索此信息?这是我的代码和相同的数据示例:

ata01 <- read.delim2('0708.txt',header = TRUE, sep = ";", dec = ".")

data01$sps[is.na(data01$sps)]<-0


special <- subset(data01, sps == 1,
                  select=c(id, geo, sps, lon, lat))
no_special <- subset(data01, sps == 0,
                     select=c(id, geo, sps, lon, lat))


sf_special <- st_as_sf(special,
                       coords = c("lon", "lat"), # x, y (order matters)
                       crs = 4326)

sf_no_special <- st_as_sf(no_special,
                          coords = c("lon", "lat"), # x, y (order matters)
                          crs = 4326)



nearest <- st_nn(sf_special,sf_no_special, k = 1, returnDist = T,  progress = FALSE)


special$dist = nn_dist$dist
special$n = nn_dist$nn

现在输出如下所示:

    id                                          geo sps      lon      lat     dist  n
8  23880 Blankartstr. 13;53474;Bad Neuenahr-Ahrweiler   1 7.102950 50.54219 2088.908  6
32 14176          Siegener Str. 26;57610;Altenkirchen   1 7.651246 50.68972 918.4893 30
35 26147        Johannes-Krell-Str. 17;57518;Betzdorf   1 7.851260 50.79092 589.7386 52
45 13408                 Schulstr.;57580;Gebhardshain   1 7.823415 50.74588 3302.691 48
46 10435              Martin-Luther-Str. 4;57577;Hamm   1 7.669567 50.76203 2005.314 38
62 23954                   Schulstr. 10;67577;Alsheim   1 8.335559 49.76163 3584.156 68

两个问题:

  1. 我想要最近学校的ID,而不是n(从“最近”开始的下一所学校的索引)!我如何使用索引来检索学校 ID 等信息?学校ID存储在sf_no_special中,但最近的索引和sf_no_special不匹配!

  2. 我还想创建一个包含 1.5 公里半径内学校数量的变量。我可以使用 nn_st 命令获取到最近的 j 所学校的距离,然后我需要对 dist < 1.500 的学校求和。有什么建议么?我试过了:

num.1500 <- apply(nearest$dist, 1, function(x) {
  sum(x < 1500)
})

但我确实得到了错误:

Error in apply(nearest$dist, 1, function(x) { : 
  dim(X) muss positive Länge haben

这是我的数据示例:

> dput(droplevels(data01[1:10, ]))
structure(list(typ = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 
1L, 1L, 1L), .Label = "Grundschule", class = "factor"), id = c(11725L, 
11739L, 26883L, 11863L, 11996L, 12060L, 22062L, 23880L, 12237L, 
12630L), str = structure(c(7L, 4L, 8L, 3L, 5L, 10L, 9L, 2L, 1L, 
6L), .Label = c("Ahrstr. 87", "Blankartstr. 13", "Eichenbacher Weg 26", 
"Kesslinger Str. 1", "Koblenzer Str.", "Quellenstr. 15", "Schulstr.", 
"Schulstr. 5", "Vehner Weg 31", "Weststr. 27"), class = "factor"), 
    plz = c(53518L, 53506L, 53505L, 53533L, 53498L, 53474L, 53474L, 
    53474L, 53505L, 56656L), ort = structure(c(1L, 2L, 3L, 4L, 
    5L, 6L, 6L, 6L, 7L, 8L), .Label = c("Adenau", "Ahrbrück", 
    "Altenahr", "Antweiler", "Bad Breisig", "Bad Neuenahr-Ahrweiler", 
    "Berg", "Brohl-Lützing"), class = "factor"), geo = structure(c(8L, 
    4L, 7L, 3L, 5L, 10L, 9L, 2L, 1L, 6L), .Label = c("Ahrstr. 87;53505;Berg", 
    "Blankartstr. 13;53474;Bad Neuenahr-Ahrweiler", "Eichenbacher Weg 26;53533;Antweiler", 
    "Kesslinger Str. 1;53506;Ahrbrück", "Koblenzer Str.;53498;Bad Breisig", 
    "Quellenstr. 15;56656;Brohl-Lützing", "Schulstr. 5;53505;Altenahr", 
    "Schulstr.;53518;Adenau", "Vehner Weg 31;53474;Bad Neuenahr-Ahrweiler", 
    "Weststr. 27;53474;Bad Neuenahr-Ahrweiler"), class = "factor"), 
    jahr = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L
    ), .Label = "2007/08", class = "factor"), name = structure(c(NA, 
    NA, NA, NA, NA, NA, NA, 1L, NA, NA), .Label = "GS Ahrweiler", class = "factor"), 
    start = structure(c(NA, NA, NA, NA, NA, NA, NA, 1L, NA, NA
    ), .Label = "2001/02", class = "factor"), sps = c(0, 0, 0, 
    0, 0, 0, 0, 1, 0, 0), lon = c(6.9325459, 6.97516, 6.9875745, 
    6.825407, 7.3035599, 7.1322642, 7.1809, 7.10295, 6.93609, 
    7.32739), lat = c(50.382685, 50.48649, 50.5085722, 50.406783, 
    50.5055535, 50.5441126, 50.54013, 50.54219, 50.52239, 50.48599
    ), dist = list(2088.90766536052, 918.489268082922, 589.738579014495, 
        3302.69115170858, 2005.31411895232, 3584.15570982643, 
        366.260782140767, 2694.12065272956, 5257.32234958339, 
        1700.27776226661), n = list(6L, 30L, 52L, 48L, 38L, 68L, 
        58L, 84L, 142L, 138L)), row.names = c(NA, 10L), class = "data.frame")
> 


> dput(droplevels(special[1:10, ]))
structure(list(id = c(23880L, 14176L, 26147L, 13408L, 10435L, 
23954L, 20647L, 26447L, 15617L, 23173L), geo = structure(c(2L, 
9L, 4L, 8L, 5L, 6L, 3L, 10L, 1L, 7L), .Label = c("Beindestr.;55569;Monzingen", 
"Blankartstr. 13;53474;Bad Neuenahr-Ahrweiler", "Donnersbergstr. 32;55232;Alzey", 
"Johannes-Krell-Str. 17;57518;Betzdorf", "Martin-Luther-Str. 4;57577;Hamm", 
"Schulstr. 10;67577;Alsheim", "Schulstr.;55593;Rüdesheim", "Schulstr.;57580;Gebhardshain", 
"Siegener Str. 26;57610;Altenkirchen", "Weinstr. 79;67169;Kallstadt"
), class = "factor"), sps = c(1, 1, 1, 1, 1, 1, 1, 1, 1, 1), 
    lon = c(7.10295, 7.6512462, 7.85126, 7.8234146, 7.6695674, 
    8.3355588, 8.1119607, 8.17405, 7.5906339, 7.8107492), lat = c(50.54219, 
    50.6897185, 50.79092, 50.7458834, 50.7620283, 49.7616261, 
    49.7408171, 49.49098, 49.7968555, 49.8468627), dist = list(
        2088.90766536052, 918.489268082922, 589.738579014495, 
        3302.69115170858, 2005.31411895232, 3584.15570982643, 
        366.260782140767, 2694.12065272956, 5257.32234958339, 
        1700.27776226661), n = list(6L, 30L, 52L, 48L, 38L, 68L, 
        58L, 84L, 142L, 138L)), row.names = c(8L, 32L, 35L, 45L, 
46L, 62L, 63L, 109L, 143L, 148L), class = "data.frame")

> dput(droplevels(no_special[1:10, ]))
structure(list(id = c(11725L, 11739L, 26883L, 11863L, 11996L, 
12060L, 22062L, 12237L, 12630L, 26537L), geo = structure(c(8L, 
4L, 7L, 2L, 5L, 10L, 9L, 1L, 6L, 3L), .Label = c("Ahrstr. 87;53505;Berg", 
"Eichenbacher Weg 26;53533;Antweiler", "Greimerstalweg 19;56659;Burgbrohl", 
"Kesslinger Str. 1;53506;Ahrbrück", "Koblenzer Str.;53498;Bad Breisig", 
"Quellenstr. 15;56656;Brohl-Lützing", "Schulstr. 5;53505;Altenahr", 
"Schulstr.;53518;Adenau", "Vehner Weg 31;53474;Bad Neuenahr-Ahrweiler", 
"Weststr. 27;53474;Bad Neuenahr-Ahrweiler"), class = "factor"), 
    sps = c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), lon = c(6.9325459, 
    6.97516, 6.9875745, 6.825407, 7.3035599, 7.1322642, 7.1809, 
    6.93609, 7.32739, 7.27089), lat = c(50.382685, 50.48649, 
    50.5085722, 50.406783, 50.5055535, 50.5441126, 50.54013, 
    50.52239, 50.48599, 50.45707)), row.names = c(1L, 2L, 3L, 
4L, 5L, 6L, 7L, 9L, 10L, 11L), class = "data.frame")

感谢您的帮助!

edit2:(预期输出)


head(special)
   id                                          geo sps      lon      lat     dist  n     ID     Radius-1500
8  23880 Blankartstr. 13;53474;Bad Neuenahr-Ahrweiler   1 7.102950 50.54219 2088.908  6
32 14176          Siegener Str. 26;57610;Altenkirchen   1 7.651246 50.68972 918.4893 30
35 26147        Johannes-Krell-Str. 17;57518;Betzdorf   1 7.851260 50.79092 589.7386 52
45 13408                 Schulstr.;57580;Gebhardshain   1 7.823415 50.74588 3302.691 48
46 10435              Martin-Luther-Str. 4;57577;Hamm   1 7.669567 50.76203 2005.314 38
62 23954                   Schulstr. 10;67577;Alsheim   1 8.335559 49.76163 3584.156 68

请检查以下代码,因为我仍然不能 100% 确定我理解您的问题。首先我需要加载一些包:

library(sf)
#> Linking to GEOS 3.8.0, GDAL 3.0.4, PROJ 6.3.1
library(nngeo)
library(tmap) # for the final map

和数据

special <- structure(
  list(
    id = c(
      23880L, 14176L, 26147L, 13408L, 10435L, 23954L, 20647L, 26447L, 15617L, 23173L
    ), 
    geo = structure(
      c(
       2L, 9L, 4L, 8L, 5L, 6L, 3L, 10L, 1L, 7L
      ), 
      .Label = c(
        "Beindestr.;55569;Monzingen", "Blankartstr. 13;53474;Bad Neuenahr-Ahrweiler", 
        "Donnersbergstr. 32;55232;Alzey", "Johannes-Krell-Str. 17;57518;Betzdorf", 
        "Martin-Luther-Str. 4;57577;Hamm", "Schulstr. 10;67577;Alsheim", 
        "Schulstr.;55593;Rudesheim", "Schulstr.;57580;Gebhardshain", 
        "Siegener Str. 26;57610;Altenkirchen", "Weinstr. 79;67169;Kallstadt"
      ), 
      class = "factor"
    ), 
    sps = c(1, 1, 1, 1, 1, 1, 1, 1, 1, 1), 
    lon = c(
      7.10295, 7.6512462, 7.85126, 7.8234146, 7.6695674, 8.3355588, 8.1119607, 
      8.17405, 7.5906339, 7.8107492
    ), 
    lat = c(
      50.54219, 50.6897185, 50.79092, 50.7458834, 50.7620283, 49.7616261, 
      49.7408171, 49.49098, 49.7968555, 49.8468627
    ), 
    dist = list(
      2088.90766536052, 918.489268082922, 589.738579014495, 3302.69115170858, 
      2005.31411895232, 3584.15570982643, 366.260782140767, 2694.12065272956, 
      5257.32234958339, 1700.27776226661
    ), 
    n = list(6L, 30L, 52L, 48L, 38L, 68L, 58L, 84L, 142L, 138L)
  ), 
  row.names = c(8L, 32L, 35L, 45L, 46L, 62L, 63L, 109L, 143L, 148L), 
  class = "data.frame"
)

# input data for "no-special"
no_special <- structure(
  list(
    id = c(
      11725L, 11739L, 26883L, 11863L, 11996L, 12060L, 22062L, 12237L, 12630L, 26537L
    ), 
    geo = structure(
      c(8L, 4L, 7L, 2L, 5L, 10L, 9L, 1L, 6L, 3L), 
      .Label = c(
        "Ahrstr. 87;53505;Berg", "Eichenbacher Weg 26;53533;Antweiler", 
        "Greimerstalweg 19;56659;Burgbrohl", "Kesslinger Str. 1;53506;Ahrbruck", 
        "Koblenzer Str.;53498;Bad Breisig", "Quellenstr. 15;56656;Brohl-Lutzing", 
        "Schulstr. 5;53505;Altenahr", "Schulstr.;53518;Adenau", 
         "Vehner Weg 31;53474;Bad Neuenahr-Ahrweiler", "Weststr. 27;53474;Bad Neuenahr Ahrweiler"
      ), 
      class = "factor"
    ), 
    sps = c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), 
    lon = c(
      6.9325459, 6.97516, 6.9875745, 6.825407, 7.3035599, 7.1322642, 7.1809, 
      6.93609, 7.32739, 7.27089
    ), 
    lat = c(
      50.382685, 50.48649, 50.5085722, 50.406783, 50.5055535, 50.5441126, 
      50.54013, 50.52239, 50.48599, 50.45707
    )
  ), 
  row.names = c(1L, 2L, 3L, 4L, 5L, 6L, 7L, 9L, 10L, 11L), 
  class = "data.frame"
)

然后我需要将数据转换成sf个对象:

sf_special <- st_as_sf(
  special,
  coords = c("lon", "lat"), # x, y (order matters)
  crs = 4326
)
sf_no_special <- st_as_sf(
  no_special, 
  coords = c("lon", "lat"), # x, y (order matters)
  crs = 4326
)

找到所有特殊和所有非特殊之间的最近邻居

nearest <- st_nn(sf_special, sf_no_special, k = 1, returnDist = FALSE, progress = FALSE)
#> lon-lat points

检查结果

nearest
#> [[1]]
#> [1] 6
#> 
#> [[2]]
#> [1] 5
#> 
#> [[3]]
#> [1] 5
#> 
#> [[4]]
#> [1] 5
#> 
#> [[5]]
#> [1] 5
#> 
#> [[6]]
#> [1] 9
#> 
#> [[7]]
#> [1] 10
#> 
#> [[8]]
#> [1] 10
#> 
#> [[9]]
#> [1] 10
#> 
#> [[10]]
#> [1] 10

该输出表示 sf_special 中的第一所学校与 sf_no_special 中的学校之间最近的邻居是 sf_no_special 中的第 6 所学校。同样的想法适用于所有其他指数。我们可以提取 sf_no_special 个 ID,如下所示:

sf_no_special[unlist(nearest), "id", drop = TRUE]
#>  [1] 12060 11996 11996 11996 11996 12630 26537 26537 26537 26537
#> attr(,"class")
#> [1] "integer"

并将该信息附加到 sf_special

sf_special$ID <- sf_no_special[unlist(nearest), "id", drop = TRUE]

检查结果

sf_special
#> Simple feature collection with 10 features and 6 fields
#> geometry type:  POINT
#> dimension:      XY
#> bbox:           xmin: 7.10295 ymin: 49.49098 xmax: 8.335559 ymax: 50.79092
#> geographic CRS: WGS 84
#>        id                                          geo sps     dist   n
#> 8   23880 Blankartstr. 13;53474;Bad Neuenahr-Ahrweiler   1 2088.908   6
#> 32  14176          Siegener Str. 26;57610;Altenkirchen   1 918.4893  30
#> 35  26147        Johannes-Krell-Str. 17;57518;Betzdorf   1 589.7386  52
#> 45  13408                 Schulstr.;57580;Gebhardshain   1 3302.691  48
#> 46  10435              Martin-Luther-Str. 4;57577;Hamm   1 2005.314  38
#> 62  23954                   Schulstr. 10;67577;Alsheim   1 3584.156  68
#> 63  20647               Donnersbergstr. 32;55232;Alzey   1 366.2608  58
#> 109 26447                  Weinstr. 79;67169;Kallstadt   1 2694.121  84
#> 143 15617                   Beindestr.;55569;Monzingen   1 5257.322 142
#> 148 23173                    Schulstr.;55593;Rudesheim   1 1700.278 138
#>                      geometry    ID
#> 8    POINT (7.10295 50.54219) 12060
#> 32  POINT (7.651246 50.68972) 11996
#> 35   POINT (7.85126 50.79092) 11996
#> 45  POINT (7.823415 50.74588) 11996
#> 46  POINT (7.669567 50.76203) 11996
#> 62  POINT (8.335559 49.76163) 12630
#> 63  POINT (8.111961 49.74082) 26537
#> 109  POINT (8.17405 49.49098) 26537
#> 143 POINT (7.590634 49.79686) 26537
#> 148 POINT (7.810749 49.84686) 26537

如果你想查看每所特殊学校15公里范围内有多少所非特殊学校,我们可以使用st_is_within_distance

no_special_within_radius <- st_is_within_distance(
  x = sf_special, 
  y = sf_no_special, 
  dist = units::set_units(15, "km")
)
no_special_within_radius
#> Sparse geometry binary predicate list of length 10, where the predicate was `is_within_distance'
#>  1: 2, 3, 5, 6, 7, 8
#>  2: (empty)
#>  3: (empty)
#>  4: (empty)
#>  5: (empty)
#>  6: (empty)
#>  7: (empty)
#>  8: (empty)
#>  9: (empty)
#>  10: (empty)

输出表示sf_no_special的学校2、3、5、6、7、8距离sf_special的第一所学校在15km以内。其他学校离他们的邻居太远了。我们可以使用函数长度计算学校数量,并将该信息添加到 sf_special:

sf_special$within_radius <- lengths(no_special_within_radius)

查看结果:

sf_special
#> Simple feature collection with 10 features and 7 fields
#> geometry type:  POINT
#> dimension:      XY
#> bbox:           xmin: 7.10295 ymin: 49.49098 xmax: 8.335559 ymax: 50.79092
#> geographic CRS: WGS 84
#>        id                                          geo sps     dist   n
#> 8   23880 Blankartstr. 13;53474;Bad Neuenahr-Ahrweiler   1 2088.908   6
#> 32  14176          Siegener Str. 26;57610;Altenkirchen   1 918.4893  30
#> 35  26147        Johannes-Krell-Str. 17;57518;Betzdorf   1 589.7386  52
#> 45  13408                 Schulstr.;57580;Gebhardshain   1 3302.691  48
#> 46  10435              Martin-Luther-Str. 4;57577;Hamm   1 2005.314  38
#> 62  23954                   Schulstr. 10;67577;Alsheim   1 3584.156  68
#> 63  20647               Donnersbergstr. 32;55232;Alzey   1 366.2608  58
#> 109 26447                  Weinstr. 79;67169;Kallstadt   1 2694.121  84
#> 143 15617                   Beindestr.;55569;Monzingen   1 5257.322 142
#> 148 23173                    Schulstr.;55593;Rudesheim   1 1700.278 138
#>                      geometry    ID within_radius
#> 8    POINT (7.10295 50.54219) 12060             6
#> 32  POINT (7.651246 50.68972) 11996             0
#> 35   POINT (7.85126 50.79092) 11996             0
#> 45  POINT (7.823415 50.74588) 11996             0
#> 46  POINT (7.669567 50.76203) 11996             0
#> 62  POINT (8.335559 49.76163) 12630             0
#> 63  POINT (8.111961 49.74082) 26537             0
#> 109  POINT (8.17405 49.49098) 26537             0
#> 143 POINT (7.590634 49.79686) 26537             0
#> 148 POINT (7.810749 49.84686) 26537             0

我们还可以绘制学校并以图形方式检查结果:

tmap_mode("view")
#> tmap mode set to interactive viewing

tm_shape(sf_special) + 
  tm_dots() + 
tm_shape(sf_no_special) + 
  tm_dots(col = "red")

reprex package (v0.3.0)

于 2020-06-29 创建