基于船速与同航次上次捕捞时间判断鱼类捕捞坐标合理性
用时间间隔+船速检测捕捞坐标错误的方法
嘿,这个问题在渔业数据清洗里太常见了——人工转录坐标很容易手抖输错,咱们用同航次的时间差+渔船最大船速就能快速揪出这些离谱的错误。核心逻辑很简单:渔船在两个捕捞点之间的航行时间里,最多能跑「时间间隔×船速」的距离,如果实际两点的地理距离超过这个值,那这个坐标大概率有问题。
下面我用你提到的R包(sf/dplyr/lubridate/ggplot2),结合你给的示例场景一步步实现:
第一步:准备示例数据(补全你的模拟数据集)
先构造一个带故意错误的数据集——比如第二个航次的第二个点,我把经度设成了离谱的125.0,方便后续检测:
library(sf) library(ggplot2) library(dplyr) library(lubridate) set.seed(123) # 保证结果可复现 fishing_data <- tibble( voyage_id = rep(c("V001", "V002"), each = 2), datetime = ymd_hms(c( "2017-05-13 14:00:00", "2017-05-13 15:30:00", # 同航次间隔1.5小时 "2017-06-01 09:00:00", "2017-06-01 09:45:00" # 同航次间隔0.75小时 ), tz = "UTC"), lon = c(120.1, 120.2, 121.0, 125.0), # 最后一个是故意设置的错误值 lat = c(30.5, 30.6, 29.8, 30.0) )
第二步:计算时间间隔与理论最大航行距离
按航次分组,计算每个捕捞点和前一个点的时间差,再结合假设的船速(比如10km/h)算出理论上能跑的最大距离:
fishing_analysis <- fishing_data %>% # 按航次分组,保证只对比同航次的点 group_by(voyage_id) %>% # 计算与上一个捕捞点的时间间隔(转成小时) mutate( time_since_last = as.numeric(difftime(datetime, lag(datetime), units = "hours")), # 计算理论最大航行距离:时间间隔×船速(这里用10km/h) max_possible_distance = time_since_last * 10 ) %>% ungroup()
第三步:计算实际地理距离并标记错误
用sf把坐标转成地理对象,计算两点间的实际球面距离,再和理论最大距离对比:
# 转成sf对象(WGS84坐标系,EPSG:4326) fishing_sf <- fishing_analysis %>% st_as_sf(coords = c("lon", "lat"), crs = 4326) %>% # 按航次分组,计算与前一个点的实际距离(转成公里) group_by(voyage_id) %>% mutate( actual_distance = as.numeric(st_distance(geometry, lag(geometry)))/1000, # 标记可疑错误:实际距离>理论最大距离(可以加个小缓冲,比如1.1倍,允许小误差) is_suspicious = ifelse(actual_distance > max_possible_distance * 1.1, TRUE, FALSE) ) %>% ungroup() # 查看结果 fishing_sf %>% select(voyage_id, datetime, actual_distance, max_possible_distance, is_suspicious) %>% st_drop_geometry()
运行后你会看到,第二个航次的最后一个点is_suspicious是TRUE——因为它的实际距离(约444公里)远大于0.75小时能跑的7.5公里,明显是错误。
第四步:可视化验证(可选但实用)
用ggplot2把航次轨迹画出来,把可疑点标红,直观确认错误:
ggplot() + # 画航次轨迹线 geom_sf(data = fishing_sf, aes(group = voyage_id), color = "gray") + # 画捕捞点,可疑点标红 geom_sf(data = fishing_sf, aes(color = is_suspicious), size = 3) + scale_color_manual(values = c("black", "red")) + labs(title = "捕捞坐标可疑错误标记", color = "是否可疑") + theme_minimal()
一些注意事项
- 船速的合理性:别随便用10km/h,最好用你渔船的实际最大巡航速度,或者行业通用的合理范围(比如小型渔船可能8-12km/h,大型拖网船可能15-20km/h)。
- 时间统一:一定要确保所有
datetime的时区一致,不然时间差计算会出错。 - 缓冲阈值:可以给理论距离加个10%-20%的缓冲,因为渔船可能绕路、记录时间有小偏差,避免误判。
- 第一个点处理:每个航次的第一个点没有前一个点,
time_since_last会是NA,可以用replace_na把is_suspicious设为FALSE。
内容的提问来源于stack exchange,提问作者sebdalgarno
相关产品推荐
相关产品推荐

