如何解决计算数据帧中多个经纬度点的中心点
site lat long
bras2 41.21 -115.11
tex4 45.3 -112.31
bras2 41.15 -115.15
bras2 41.12 -115.19
对于具有相同 site
名称的样本,我想计算它们的中心点,然后将其作为一列添加到数据集中。一些 site
名称重复两次,其他 3 次,其他 4 次。
像这样:
site lat long centre_lat centre_long
bras2 41.21 -115.11 value here value here
tex4 45.3 -112.31 45.3 -112.31
bras2 41.15 -115.15 value here value here
bras2 41.12 -115.19 value here value here
我该怎么做?
解决方法
如果您使用空间数据,您应该考虑使用 pylint *
包。它处理几何图形和函数以很好地对其进行操作。
下面的代码显示同时使用 sf
和 sf::st_centroid
。我更喜欢geosphere::centroid
的做事方式。
sf
看起来它们足够接近同一点。我不认为 df <- read.table(header=TRUE,text= "site lat long
bras2 41.21 -115.11
tex4 45.3 -112.31
bras2 41.15 -115.15
bras2 41.12 -115.19")
library(dplyr)
library(geosphere)
library(sf)
# Using sf's st_centroid
df_sf <- st_as_sf(df,coords = c('long','lat'))
centroids_sf <- df_sf %>%
group_by(site) %>%
summarize(geometry = st_union(geometry)) %>%
st_centroid
# Using geosphere::centroid
centroids_geoshpere <- df_sf %>%
group_by(site) %>%
filter(n() >2) %>% ## geosphere needs polygons therefore 3+ points
st_union() %>%
st_cast('POLYGON') %>%
as('Spatial') %>% # geoshpere expects SpatialPolygons objects
centroid()
centroids_geoshpere
#> [,1] [,2]
#> [1,] -115.15 41.16001
centroids_sf
#> Simple feature collection with 2 features and 1 field
#> geometry type: POINT
#> dimension: XY
#> bbox: xmin: -115.15 ymin: 41.16 xmax: -112.31 ymax: 45.3
#> CRS: NA
#> # A tibble: 2 x 2
#> site geometry
#> * <chr> <POINT>
#> 1 bras2 (-115.15 41.16)
#> 2 tex4 (-112.31 45.3)
可以为单个点提供质心,但可能是错误的。 geosphere::centroid
有 1,2 或更多点没有问题。
由 reprex package (v0.3.0) 于 2020 年 12 月 20 日创建
在使用 ave
去除站点编号后,您可以使用 gsub
计算按站点名称分组的平均值。
within(dat,{
g <- gsub("\\d","",site)
mid.lat <- ave(lat,g)
mid.long <- ave(long,g)
rm(g)
})
# site lat long mid.long mid.lat
# 1 bras2 41.21 -115.11 -115.150 41.160
# 2 tex4 45.30 -112.31 -112.310 45.300
# 3 bras2 41.15 -115.15 -115.150 41.160
# 4 bras2 41.12 -115.19 -115.150 41.160
# 5 foo1 42.10 -123.10 -123.225 42.225
# 6 foo2 42.20 -123.20 -123.225 42.225
# 7 foo11 42.30 -123.30 -123.225 42.225
# 8 foo12 42.30 -123.30 -123.225 42.225
或者,如果您依赖于 NA
:
within(dat,site)
n <- ave(site,g,FUN=length)
mid.lat <- NA
mid.long <- NA
mid.lat[n > 1] <- ave(lat[n > 1],g[n > 1])
mid.long[n > 1] <- ave(long[n > 1],g[n > 1])
rm(g,n)
})
# site lat long mid.long mid.lat
# 1 bras2 41.21 -115.11 -115.150 41.160
# 2 tex4 45.30 -112.31 NA NA
# 3 bras2 41.15 -115.15 -115.150 41.160
# 4 bras2 41.12 -115.19 -115.150 41.160
# 5 foo1 42.10 -123.10 -123.225 42.225
# 6 foo2 42.20 -123.20 -123.225 42.225
# 7 foo11 42.30 -123.30 -123.225 42.225
# 8 foo12 42.30 -123.30 -123.225 42.225
数据:
dat <- structure(list(site = c("bras2","tex4","bras2","foo1","foo2","foo11","foo12"),lat = c(41.21,45.3,41.15,41.12,42.1,42.2,42.3,42.3),long = c(-115.11,-112.31,-115.15,-115.19,-123.1,-123.2,-123.3,-123.3)),class = "data.frame",row.names = c(NA,-8L))
,
geosphere 包有一个函数 centroid
来解决诸如此类的问题。
它只要有一个以上的形状它就是直截了当的。下面的大部分代码都涉及处理上面示例中的单点情况。
df <- read.table(header=TRUE,text= "site lat long
bras2 41.21 -115.11
tex4 45.3 -112.31
bras2 41.15 -115.15
bras2 41.12 -115.19")
library(dplyr)
library(geosphere)
df %>% group_by(side) %>% centroid(.[,c(3,2)])
sites <- split(df,df$site)
results <-lapply(sites,function(x) {
if(nrow(x)>1 ) {
value <- as.data.frame(centroid(x[,2)]))
}
else {
value <- x[1,2)]
names(value) <- c("lon","lat")
}
value$site <- x$site[1]
value
})
answer<-bind_rows(results)
lon lat site
1 -115.15 41.16001 bras2
2 -112.31 45.30000 tex4
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。