R语言数据预处理:按最短长度筛选唯一起止点记录
R语言实现线段起终点全局唯一清洗
清洗规则说明
- 所有记录的起点
s全局不重复,同一起点仅保留seg_length最短的记录 - 所有记录的终点
e全局不重复,同一终点仅保留seg_length最短的记录 - 由于单次筛选起点后可能产生新的重复终点,单次筛选终点后也可能产生新的重复起点,代码采用迭代收敛逻辑,直到筛选后数据行数不再变化,即满足全局起终点唯一要求。
- 同分组下如果存在多条
seg_length相等的记录,默认保留FID最小的一条,可按需调整规则。
示例数据构造
先复现提供的测试数据集:
df <- data.frame( FID = 0:7, osmid = c(4999, 566, 499, 56, 409, 516, 459, 526), s = c(733, 733, 713, 783, 783, 736, 739, 731), e = c(99, 33, 96, 32, 98, 38, 98, 33), seg_length = c(7.7, 3.2, 7.7, 3.5, 7.6, 3.5, 7.7, 3.2) )
实现代码
dplyr版本(推荐,代码可读性高)
首次使用请先运行安装命令install.packages("dplyr")加载依赖:
library(dplyr) clean_seg <- function(raw_data) { df_cur <- raw_data repeat { n_prev <- nrow(df_cur) # 按起点分组筛最短 df_cur <- df_cur %>% group_by(s) %>% filter(seg_length == min(seg_length), FID == min(FID)) %>% ungroup() # 按终点分组筛最短 df_cur <- df_cur %>% group_by(e) %>% filter(seg_length == min(seg_length), FID == min(FID)) %>% ungroup() # 收敛判断 if (nrow(df_cur) == n_prev) break } return(df_cur) } # 执行清洗 df_cleaned <- clean_seg(df)
Base R版本(无第三方依赖)
不需要安装任何包,直接运行即可:
clean_seg_base <- function(raw_data) { df_cur <- raw_data repeat { n_prev <- nrow(df_cur) # 筛起点重复 s_min <- tapply(df_cur$seg_length, df_cur$s, min) df_cur <- df_cur[df_cur$seg_length == s_min[as.character(df_cur$s)], ] df_cur <- df_cur[!duplicated(df_cur$s), ] # 筛终点重复 e_min <- tapply(df_cur$seg_length, df_cur$e, min) df_cur <- df_cur[df_cur$seg_length == e_min[as.character(df_cur$e)], ] df_cur <- df_cur[!duplicated(df_cur$e), ] # 收敛判断 if (nrow(df_cur) == n_prev) break } return(df_cur) } df_cleaned <- clean_seg_base(df)
清洗结果
针对提供的测试数据,最终清洗结果如下,完全符合规则要求:
| FID | osmid | s | e | seg_length |
|---|---|---|---|---|
| 1 | 566 | 733 | 33 | 3.2 |
| 2 | 499 | 713 | 96 | 7.7 |
| 3 | 56 | 783 | 32 | 3.5 |
| 5 | 516 | 736 | 38 | 3.5 |
| 6 | 459 | 739 | 98 | 7.7 |
提到的FID4和FID6共享终点98的场景中,FID4因为和FID3共享起点783且长度更长,会在第一轮起点筛选阶段被移除,最终保留FID6作为终点98的唯一记录,这是迭代规则下的正常结果。如果业务需要优先保留终点匹配的最短记录,可以调整迭代顺序(先筛终点再筛起点)即可。
内容的提问来源于stack exchange,提问作者user18343293
相关产品推荐
相关产品推荐

