Apache Spark Scala:如何检测时间区间交集并进行分组?
解决时间区间分组问题
核心逻辑:判断两个时间区间是否有交集
两个时间区间 [s1, e1] 和 [s2, e2] 存在交集的充要条件是:s1 < e2 且 s2 < e1
简单解释:只要一个区间的开始时间早于另一个区间的结束时间,且另一个区间的开始时间也早于这个区间的结束时间,就说明两个区间有重叠或相交部分。
实现步骤(处理无序数据)
因为数据是随机排序的,直接逐个判断效率低,推荐先排序再用贪心算法合并重叠区间,最后给原始数据分配组号。
1. 准备数据并确保日期类型
首先将start和end列转换为datetime类型(如果尚未转换):
import pandas as pd # 构造示例数据 data = { 'start': ['2019-07-01 10:01:19.000', '2019-07-01 10:10:05.000', '2019-07-01 10:35:00.000', '2019-07-01 15:20:00.000', '2019-07-01 16:10:00.000', '2019-07-01 16:30:00.000'], 'end': ['2019-07-01 10:11:00.000', '2019-07-01 10:40:00.000', '2019-07-01 12:30:00.000', '2019-07-01 15:50:00.000', '2019-07-01 16:35:00.000', '2019-07-01 17:00:00.000'] } df = pd.DataFrame(data) # 转换为datetime类型 df['start'] = pd.to_datetime(df['start']) df['end'] = pd.to_datetime(df['end'])
2. 排序并合并重叠区间
先按start列排序,然后遍历合并所有相交或重叠的区间,记录每个组的范围:
# 按start排序,方便后续合并 sorted_df = df.sort_values('start').reset_index(drop=True) # 初始化合并后的区间列表,每个元素包含组号、组的起始和结束时间 merged_groups = [] for idx, row in sorted_df.iterrows(): if not merged_groups: # 第一个区间直接作为第一组 merged_groups.append({'group': 1, 'group_start': row['start'], 'group_end': row['end']}) else: last_group = merged_groups[-1] # 判断当前区间和最后一个合并组是否有交集 if row['start'] < last_group['group_end']: # 有交集,合并组的结束时间为两者的最大值 last_group['group_end'] = max(last_group['group_end'], row['end']) else: # 无交集,新增一个组 merged_groups.append({ 'group': len(merged_groups) + 1, 'group_start': row['start'], 'group_end': row['end'] })
3. 给原始数据分配组号
遍历原始数据的每个区间,判断它属于哪个合并后的组:
def assign_group(row): for group_info in merged_groups: # 判断当前区间和组区间是否有交集 if row['start'] < group_info['group_end'] and group_info['group_start'] < row['end']: return group_info['group'] # 理论上不会走到这里,除非有完全独立的新区间 return len(merged_groups) + 1 # 新增group列 df['group'] = df.apply(assign_group, axis=1)
最终结果
运行上述代码后,你的DataFrame会生成group列,结果和你期望的一致:
| start | end | group |
|---|---|---|
| 2019-07-01 10:01:19.000 | 2019-07-01 10:11:00.000 | 1 |
| 2019-07-01 10:10:05.000 | 2019-07-01 10:40:00.000 | 1 |
| 2019-07-01 10:35:00.000 | 2019-07-01 12:30:00.000 | 1 |
| 2019-07-01 15:20:00.000 | 2019-07-01 15:50:00.000 | 2 |
| 2019-07-01 16:10:00.000 | 2019-07-01 16:35:00.000 | 3 |
| 2019-07-01 16:30:00.000 | 2019-07-01 17:00:00.000 | 3 |
内容的提问来源于stack exchange,提问作者svg_af_2
相关产品推荐
相关产品推荐

