根据地理距离矩阵的结果更改列
Alter a column based on results from geodistance matrix
我有一个如下所示的数据框:
long lat site
-141.37 61.13 x1
-149.1833 66.7333 x2
-149.667 67.667 x3
-141.3667 61.1157 x4
我想使用 distVincentyEllipsoid
计算所有 site
之间的距离。然后对于彼此相距 5 公里以内的那些站点,我想修改 site
名称以包含这两个站点。所以,在这个例子中 x1
和 x4
相距不到 5 公里,所以它会是这样的:
long lat site
-141.37 61.13 x1_x4
-149.1833 66.7333 x2
-149.667 67.667 x3
-141.3667 61.1157 x1_x4
我知道我可以用这种方式计算所有 site
之间的矩阵:
df %>% dplyr::select('long', 'lat')
distm(df, fun = distVincentyEllipsoid)
但我不知道如何从那里获取它。
如果您将示例数据作为 R 代码提供,这将很有帮助,就像这样
x <- matrix(c(-141.37, 61.13, -149.1833, 66.7333, -149.667, 67.667, -141.3667, 61.1157), ncol=2, byrow=TRUE)
colnames(x) <- c("lon", "lat")
x <- data.frame(site=paste0("x", 1:4), x)
但感谢您展示预期的输出
解决方案:
按照你的建议,先做一个距离矩阵。然后将其分类为是否在阈值距离内,然后使用行 select 记录。请注意,我使用 distGeo
--- 这是比 distVincentyEllipsoid
.
更好的方法
library(geosphere)
m <- distm(x[, c("lon", "lat")], fun=distGeo)
m <- m < 5000
x$name <- apply(m, 1, function(i) paste(x$site[i], collapse="_"))
x
# site lon lat name
#1 x1 -141.3700 61.1300 x1_x4
#2 x2 -149.1833 66.7333 x2
#3 x3 -149.6670 67.6670 x3
#4 x4 -141.3667 61.1157 x1_x4
如果点很多,距离矩阵可能会变得太大。在那种情况下你可以做
y <- x[, c("lon", "lat")]
for (i in 1:nrow(y)) {
j <- distGeo(y[i, ], y) < 5000
x$name[i] <- paste(x$site[j], collapse="_")
}
或者像这样
y <- x[, c("lon", "lat")]
x$name <- x$site
for (i in 1:nrow(y)) {
j <- distGeo(y[i, ], y) < 5000
if (any(j)) {
x$name[i] <- paste(x$site[j], collapse="_")
}
}
这是一个使用 tidyverse
的答案:
library(geosphere)
dist_mat <- distm(select(df, long, lat), fun = distVincentyEllipsoid)
df %>%
mutate(site_new = map_chr(1:n(), ~paste0(df$site[which(dist_mat[,.x] <= 5000)], collapse = "_")))
# A tibble: 4 x 4
long lat site site_new
<dbl> <dbl> <chr> <chr>
1 -141. 61.1 x1 x1_x4
2 -149. 66.7 x2 x2
3 -150. 67.7 x3 x3
4 -141. 61.1 x4 x1_x4
我有一个如下所示的数据框:
long lat site
-141.37 61.13 x1
-149.1833 66.7333 x2
-149.667 67.667 x3
-141.3667 61.1157 x4
我想使用 distVincentyEllipsoid
计算所有 site
之间的距离。然后对于彼此相距 5 公里以内的那些站点,我想修改 site
名称以包含这两个站点。所以,在这个例子中 x1
和 x4
相距不到 5 公里,所以它会是这样的:
long lat site
-141.37 61.13 x1_x4
-149.1833 66.7333 x2
-149.667 67.667 x3
-141.3667 61.1157 x1_x4
我知道我可以用这种方式计算所有 site
之间的矩阵:
df %>% dplyr::select('long', 'lat')
distm(df, fun = distVincentyEllipsoid)
但我不知道如何从那里获取它。
如果您将示例数据作为 R 代码提供,这将很有帮助,就像这样
x <- matrix(c(-141.37, 61.13, -149.1833, 66.7333, -149.667, 67.667, -141.3667, 61.1157), ncol=2, byrow=TRUE)
colnames(x) <- c("lon", "lat")
x <- data.frame(site=paste0("x", 1:4), x)
但感谢您展示预期的输出
解决方案:
按照你的建议,先做一个距离矩阵。然后将其分类为是否在阈值距离内,然后使用行 select 记录。请注意,我使用 distGeo
--- 这是比 distVincentyEllipsoid
.
library(geosphere)
m <- distm(x[, c("lon", "lat")], fun=distGeo)
m <- m < 5000
x$name <- apply(m, 1, function(i) paste(x$site[i], collapse="_"))
x
# site lon lat name
#1 x1 -141.3700 61.1300 x1_x4
#2 x2 -149.1833 66.7333 x2
#3 x3 -149.6670 67.6670 x3
#4 x4 -141.3667 61.1157 x1_x4
如果点很多,距离矩阵可能会变得太大。在那种情况下你可以做
y <- x[, c("lon", "lat")]
for (i in 1:nrow(y)) {
j <- distGeo(y[i, ], y) < 5000
x$name[i] <- paste(x$site[j], collapse="_")
}
或者像这样
y <- x[, c("lon", "lat")]
x$name <- x$site
for (i in 1:nrow(y)) {
j <- distGeo(y[i, ], y) < 5000
if (any(j)) {
x$name[i] <- paste(x$site[j], collapse="_")
}
}
这是一个使用 tidyverse
的答案:
library(geosphere)
dist_mat <- distm(select(df, long, lat), fun = distVincentyEllipsoid)
df %>%
mutate(site_new = map_chr(1:n(), ~paste0(df$site[which(dist_mat[,.x] <= 5000)], collapse = "_")))
# A tibble: 4 x 4
long lat site site_new
<dbl> <dbl> <chr> <chr>
1 -141. 61.1 x1 x1_x4
2 -149. 66.7 x2 x2
3 -150. 67.7 x3 x3
4 -141. 61.1 x4 x1_x4