基于Pandas检测含街道维度的邮件地址数值范围重叠问题
处理带街道维度的数值范围重叠检测问题
嘿,我懂你现在卡在哪了——把二维的范围重叠检测拓展到带街道维度的场景,确实得调整下思路。给你梳理一套实用、贴合Pandas逻辑的方案,比单纯用集合交集高效多了:
核心思路:按街道分组,组内检测范围重叠
只有同一条街道的数值范围才需要判断是否重叠,所以第一步肯定是用groupby按street_name分组,然后在每个组内单独处理范围重叠的判断,这样就把三维问题拆解成了多个二维问题来解决。
高效的范围重叠判断公式
先给你一个通用的范围重叠判断逻辑:假设我们有两个范围[a_start, a_end]和[b_start, b_end](先确保每个范围的起始值≤结束值),它们重叠的条件是:
a_start <= b_end 且 b_start <= a_end
这个公式比转换成集合交集高效太多——尤其是当范围很大的时候(比如范围是1到100000,转集合会占大量内存,计算速度还慢),而且支持所有数值类型(包括小数,而range只能处理整数)。
完整实现代码
结合你已经完成的重复值处理,我们可以在分组后对每个街道的范围进行两两比对,找出所有重叠的记录:
import pandas as pd # 读取数据并处理重复值(你的原有代码) df = pd.read_csv('Main_Street.csv') df = df[df.duplicated(subset=['street_name', 'start_range', 'end_range'], keep=False)] # 先统一修正范围:确保start_range <= end_range(避免数据里的异常情况) df['start_range'] = df[['start_range', 'end_range']].min(axis=1) df['end_range'] = df[['start_range', 'end_range']].max(axis=1) # 定义函数:在单个街道的分组内,找出所有重叠的范围对 def find_overlapping_ranges(group): overlap_records = [] # 遍历组内每条记录,和其他记录做比对 for idx_i, row_i in group.iterrows(): for idx_j, row_j in group.iterrows(): # 跳过自己和已经比对过的组合(避免重复记录) if idx_i >= idx_j: continue # 应用重叠判断公式 if row_i['start_range'] <= row_j['end_range'] and row_j['start_range'] <= row_i['end_range']: # 计算具体的重叠区间 overlap_start = max(row_i['start_range'], row_j['start_range']) overlap_end = min(row_i['end_range'], row_j['end_range']) overlap_records.append({ 'street_name': row_i['street_name'], 'range_1': f"{row_i['start_range']}-{row_i['end_range']}", 'range_2': f"{row_j['start_range']}-{row_j['end_range']}", 'overlap_interval': f"[{overlap_start}, {overlap_end}]" }) return pd.DataFrame(overlap_records) # 按街道分组处理,合并所有结果 overlap_results = df.groupby('street_name').apply(find_overlapping_ranges).reset_index(drop=True) # 查看最终结果 print(overlap_results)
关于集合交集方法的补充说明
你提到的集合交集方法确实能检测重叠,但有两个明显的局限性:
- 效率低下:如果范围跨度大(比如从1到100000),转换成集合会占用巨量内存,计算速度也很慢;
- 适用性窄:只能处理整数范围,要是你的数据里有小数,
range就完全用不了了。
如果你的数据范围都是小整数,集合方法也可以在分组后使用,但上面的公式法是更通用、高效的解决方案。
测试你的示例场景
针对你提到的Main Street 850-850和Main Street 800-899,运行上面的代码会输出:
street_name range_1 range_2 overlap_interval 0 Main Street 850-850 800-899 [850, 850]
内容的提问来源于stack exchange,提问作者John S
相关产品推荐
相关产品推荐

