[英]Calculate a centre point of multiple lat, long points in a data-frame
我有一個如下所示的數據集:
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
名稱重復兩次,其他三次,其他四次。
像這樣:
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
我怎樣才能做到這一點?
如果您使用的是空間數據,您應該考慮使用sf
package。 它可以很好地處理幾何圖形和函數。
下面的代碼顯示了同時使用sf::st_centroid
和 geosphere 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
可以為單個點提供質心,但可能是錯誤的。 sf::st_centroid
對於 1,2 或更多點沒有問題。 由代表 package (v0.3.0) 於 2020 年 12 月 20 日創建
在使用gsub
剝離站點編號后,您可以使用ave
計算按站點名稱分組的平均值。
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, {
g <- gsub("\\d", "", 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", "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))
地圈 package 有一個 function 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[, c(3,2)]))
}
else {
value <- x[1, c(3,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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.