如何在按ID拆分的数据集列表中循环执行st_distance及解决geosphere::bearing运行报错问题
嘿,我来帮你搞定这两个问题——先解决geosphere::bearing的报错,再聊聊怎么在拆分后的列表里用st_distance计算距离。
一、解决geosphere::bearing的报错
你遇到的Error in .pointsToMatrix(p1) : 'list' object cannot be coerced to type 'double',原因很直接:geosphere包的函数不接受sf对象,它需要的是数值型的经纬度矩阵或数据框,而你用st_as_sf把x/y转成了sf对象,这就导致了类型不匹配。
另外注意:geosphere的函数是基于WGS84地理坐标系的,应该用你数据里的Long和Lat列(经纬度),而不是投影后的x/y坐标。修正后的代码如下:
library(dplyr) library(purrr) library(sf) library(geosphere) # 按ID拆分数据 dis_list <- split(data, data$ID) # 修正后的方位角计算 answer <- lapply(dis_list, function(df) { # 提取相邻点的经纬度:start是后一行,end是前一行 start <- df[-1, c("Long", "Lat")] end <- df[-nrow(df), c("Long", "Lat")] # geosphere::bearing可以直接接收数据框输入 angles <- geosphere::bearing(start, end) # 把结果添加到原数据,第一行设为NA(无前置点) df$angles <- c(NA, angles) df }) # 合并回一个完整数据框(可选) answer_df <- bind_rows(answer)
二、在拆分后的列表中使用st_distance
st_distance是sf包的函数,需要先把每个子数据框转成sf对象,并且必须指定正确的坐标系(因为你的x/y是投影后的坐标)。步骤如下:
# 循环计算每个ID的相邻点距离 distance_list <- lapply(dis_list, function(df) { # 转成sf对象:用投影后的x/y作为坐标,替换成你实际的CRS(比如EPSG:32615,按需修改) sf_df <- st_as_sf(df, coords = c("x", "y"), crs = 32615) # 计算相邻点的距离:by_element=TRUE返回向量而非矩阵 distances <- st_distance(sf_df[-1, ], sf_df[-nrow(sf_df), ], by_element = TRUE) # 把距离添加到原数据,第一行设为NA df$distance_m <- c(NA, as.numeric(distances)) df }) # 合并回总数据框 distance_df <- bind_rows(distance_list)
如果你更习惯用purrr的语法,也可以写成:
distance_list_purrr <- dis_list %>% map(function(df) { sf_df <- st_as_sf(df, coords = c("x", "y"), crs = 32615) distances <- st_distance(sf_df[-1, ], sf_df[-nrow(sf_df), ], by_element = TRUE) df$distance_m <- c(NA, as.numeric(distances)) df }) distance_df_purrr <- bind_rows(distance_list_purrr)
关键注意点
- 用
geosphere时,一定要用地理坐标系的经纬度(Long/Lat),不要用投影后的坐标; - 用
st_distance时,必须给sf对象指定正确的crs,这样计算出的距离单位才是正确的(比如米); st_distance的by_element = TRUE参数非常实用,可以直接得到每个点对的距离向量,不用再从矩阵里提取值。
内容的提问来源于stack exchange,提问作者Beardedant
相关产品推荐
相关产品推荐

