如何用Python Pandas合并同国家且首尾数值衔接的DataFrame行?
合并DataFrame中同国家连续区间行的解决方案
问题背景
现有一个已按low_number排序的DataFrame:
Country_code country low_number high_number ----------------------------------------------------- AU Australia 1 10 FR France 2 45 AU Australia 10 23 AU Australia 30 43 AU Australia 43 55 FR France 45 55 FR France 67 80 FR France 80 98
需求是:合并同一国家(或Country_code)的连续行——当某行的high_number等于同国家下一行的low_number时,将这些连续区间合并为一行,保留该组的最小low_number和最大high_number,最终输出:
Country_code country low_number high_number ----------------------------------------------------- AU Australia 1 23 FR France 2 55 AU Australia 30 55 FR France 67 98
解决方案
核心思路是先按国家分组,在每组内标记出独立的合并区间,再对每个区间聚合计算最小/最大值,同时保留其他固定列。
步骤1:标记合并区间的分组键
按country分组后,判断当前行的low_number是否等于上一行的high_number,通过累计求和生成区分不同区间的分组键:
import pandas as pd # 假设你的DataFrame名为df df['group_key'] = df.groupby('country').apply( lambda g: (g['low_number'] != g['high_number'].shift(1)).cumsum() ).reset_index(level=0, drop=True)
- 当当前行的
low_number和上一行的high_number不相等时,会生成新的分组键,确保连续可合并的行归为同一组。
步骤2:按国家+分组键聚合
按country和group_key分组,聚合时保留Country_code(取组内第一个值即可,同国家的Country_code一致),计算low_number的最小值和high_number的最大值:
result = df.groupby(['country', 'group_key'], as_index=False).agg( Country_code=('Country_code', 'first'), low_number=('low_number', 'min'), high_number=('high_number', 'max') )
步骤3:整理最终结果
删除临时的group_key列,按low_number排序还原原数据的顺序:
result = result.drop('group_key', axis=1).sort_values('low_number').reset_index(drop=True)
完整代码示例
import pandas as pd # 构造示例数据 data = [ ['AU', 'Australia', 1, 10], ['FR', 'France', 2, 45], ['AU', 'Australia', 10, 23], ['AU', 'Australia', 30, 43], ['AU', 'Australia', 43, 55], ['FR', 'France', 45, 55], ['FR', 'France', 67, 80], ['FR', 'France', 80, 98] ] df = pd.DataFrame(data, columns=['Country_code', 'country', 'low_number', 'high_number']) # 标记合并区间组键 df['group_key'] = df.groupby('country').apply( lambda g: (g['low_number'] != g['high_number'].shift(1)).cumsum() ).reset_index(level=0, drop=True) # 聚合合并 result = df.groupby(['country', 'group_key'], as_index=False).agg( Country_code=('Country_code', 'first'), low_number=('low_number', 'min'), high_number=('high_number', 'max') ) # 整理结果 result = result.drop('group_key', axis=1).sort_values('low_number').reset_index(drop=True) print(result)
运行后输出:
Country_code country low_number high_number 0 AU Australia 1 23 1 FR France 2 55 2 AU Australia 30 55 3 FR France 67 98
内容的提问来源于stack exchange,提问作者Arsenfat
相关产品推荐
相关产品推荐

