如何按相似非匹配值分组Pandas DataFrame?满足id、amount相同且num差值≤10
解决方案
要实现你描述的分组规则,核心是先按id和amount进行初步分组,再在每个子组内根据num的相邻差值(排序后)拆分出子分组,最后生成全局唯一的分组ID。以下是具体实现步骤:
1. 构造示例DataFrame
首先还原你提供的示例数据:
import pandas as pd data = { 'id': ['aaa-aaa', 'aaa-aaa', 'bbb-bbb', 'ccc-ccc', 'bbb-bbb', 'aaa-aaa', 'aaa-aaa'], 'amount': [130, 130, 270, 130, 270, 130, 380], 'num': [12, 39, 41, 19, 37, 42, 39] } df = pd.DataFrame(data)
2. 定义子分组分配函数
这个函数会处理每个(id, amount)组合的子数据集:
- 先按
num排序,确保能正确计算相邻值的差值 - 判断相邻
num的绝对值差是否超过10,超过则标记为新分组的起点 - 累积求和生成子组内的分组编号
def assign_subgroup(sub_df): # 按num排序,保证差值计算的合理性 sorted_sub = sub_df.sort_values('num').reset_index(drop=True) # 计算相邻num的绝对值差,第一行差值为NaN num_diff = sorted_sub['num'].diff().abs() # 标记新分组的起点:第一行 或 差值超过10 new_group_flag = (num_diff > 10) | num_diff.isna() # 累积求和得到子组内的分组ID sorted_sub['sub_group'] = new_group_flag.cumsum() # 合并回原数据,保留原始行顺序 return sub_df.merge(sorted_sub[['num', 'sub_group']], on='num', how='left')
3. 应用分组并生成全局分组ID
对原DataFrame按id和amount分组,应用上述函数,再将(id, amount, sub_group)的组合映射为全局唯一的分组编号:
# 为每个(id, amount)子组分配子分组ID df_with_subgroup = df.groupby(['id', 'amount'], group_keys=False).apply(assign_subgroup) # 生成全局分组ID映射 unique_groups = df_with_subgroup[['id', 'amount', 'sub_group']].drop_duplicates() group_mapping = {tuple(row): idx+1 for idx, row in enumerate(unique_groups.itertuples(index=False))} # 为每行分配全局分组ID df_with_subgroup['group_id'] = df_with_subgroup.apply( lambda x: group_mapping[(x['id'], x['amount'], x['sub_group'])], axis=1 )
4. 查看结果
执行后,df_with_subgroup中的group_id列就是你需要的分组编号,输出结果如下:
id amount num sub_group group_id 0 aaa-aaa 130 12 1 1 1 aaa-aaa 130 39 2 2 2 bbb-bbb 270 41 1 3 3 ccc-ccc 130 19 1 4 4 bbb-bbb 270 37 1 3 5 aaa-aaa 130 42 2 2 6 aaa-aaa 380 39 1 5
完全符合你预期的分组规则:
- 分组1:仅含
aaa-aaa、130、12的行 - 分组2:含
aaa-aaa、130、39和42的行 - 分组3:含
bbb-bbb、270、41和37的行 - 分组4:仅含
ccc-ccc、130、19的行 - 分组5:仅含
aaa-aaa、380、39的行
内容的提问来源于stack exchange,提问作者yem
相关产品推荐
相关产品推荐

