R语言基于空间相交匹配实现同门店坐标数据合并
多源门店坐标匹配聚合实现方案
你的思路逻辑成立,核心需要补全两个容易踩坑的点:一是空间缓冲区计算必须转米制投影,不能直接在经纬度坐标下生成缓冲区;二是两两空间相交的结果需要做连通性聚类,才能把「A与B相交、B与C相交但A与C不直接相交」的同门店点归到同一组。
完整实现流程
- 加载依赖包,将原始数据转为sf空间对象,转换为米制投影后生成100米半径缓冲区
- 按清洗后的
name_key字段分组,组内计算所有缓冲区的空间相交关系 - 将相交关系转为无向图,通过连通分量识别生成唯一
group_id,同一连通分量下的点对应同一个实体门店 - 按
group_id聚合所有关联品牌,完成匹配
可直接运行的测试代码
library(tidyverse) library(sf) library(igraph) # 原始测试数据 tt <- tibble(lat = c(41.38702918, 41.386601, 41.38744179, 41.3871449, 41.38896353, 41.38963478, 41.38666041, 41.38598465, 41.3867169, 41.3852132453, 41.38438262), long = c(2.170086301, 2.16939207, 2.17080332, 2.171450558, 2.167685415, 2.16892721, 2.170950285, 2.171100009, 2.171736392, 2.171215346, 2.170955304), name = c( "El Corte Inglés", "EL CORTE INGLÉS DIAGONAL (007)", "El Corte Inglés", "El Corte Inglés Barcelona", "Nadons", "Pops And Co", "Bitti", "BITTI", "BITTI", "Bitti", "Bitti"), brand = c( "b", "s", "c", "e", "e", "c", "m", "c", "s", "e", "b") ) %>% mutate(name_key = tolower(name), name_key = iconv(name_key, from="UTF-8",to="ASCII//TRANSLIT"), name_key = str_remove_all(name_key, '[[:digit:]]'), name_key = str_remove_all(name_key, '[:punct:]'), name_key = str_remove_all(name_key, '[:space:]'), name_key = str_remove_all(name_key, 'ltda'), name_key = str_remove_all(name_key, 'ltd'), name_key = str_sub(name_key, end = 5L), # 给原始数据加行号作为唯一点id point_id = row_number()) # 生成空间对象、转米制投影、做100米缓冲区 # 测试样本位于巴塞罗那,对应米制投影选EPSG:25831,国内数据可换对应区域的UTM或CGCS2000投影 tt_sf <- tt %>% st_as_sf(coords = c("long", "lat"), crs = 4326) %>% st_transform(crs = 25831) %>% mutate(buffer = st_buffer(geometry, dist = 100)) # 按name_key分组计算连通组id tt_with_group <- tt_sf %>% group_by(name_key) %>% group_modify(~{ # 组内点数小于等于1直接返回,group_id为自身point_id if(nrow(.x) <=1) { return(.x %>% mutate(group_id = point_id)) } # 计算组内缓冲区的相交邻接矩阵 intersect_mat <- st_intersects(.x$buffer, .x$buffer, sparse = F) # 构建无向图,找连通分量 g <- graph_from_adjacency_matrix(intersect_mat, mode = "undirected", diag = F) comp <- components(g)$membership # 生成全局唯一group_id:name_key + 组内分量id .x %>% mutate(group_id = paste0(.y$name_key, "_", comp)) }) %>% ungroup() # 按group_id聚合所有入驻品牌 store_brand_map <- tt_with_group %>% st_drop_geometry() %>% group_by(group_id) %>% summarise( all_brands = paste0(unique(brand), collapse = ","), store_names = paste0(unique(name), collapse = " | "), point_count = n() ) # 如果需要可视化验证,可直接用之前的leaflet代码,把group_id加到label里即可
参数调整说明
- 缓冲区半径:根据你爬取的多源数据坐标偏差幅度调整,若多数同门店点偏差在50米内可设为50,偏差大可适当上调,避免把相邻的不同门店误合并
- name_key清洗规则:可根据你的数据特征新增清理规则,比如去掉"inc"、"shop"、"store"等通用后缀,进一步降低误匹配概率
- 性能优化:如果数据量超过10万条,按
name_key分组后再做空间计算的逻辑已经能大幅降低计算量,不需要全局做空间相交匹配
内容的提问来源于stack exchange,提问作者Xavier
相关产品推荐
相关产品推荐

