如何用Python合并含重叠数据且有特殊规则的两个DataFrame
基于规则的DataFrame合并实现方案
核心逻辑梳理
- 按
ID分组处理,确保区间判断仅在同一ID范围内生效 - 识别连续20英尺(即4个连续5英尺子区间)且所有df1数值列全为-99的片段
- 仅对符合条件的片段用df2数据覆盖df1,其余场景完全保留df1数据
- 自动处理列差异:保留两个DataFrame的所有列,df1列优先,df2补充df1缺失的列
代码实现
1. 导入依赖与加载数据(示例)
import pandas as pd import numpy as np # 替换为你实际的数据加载代码 df1 = pd.DataFrame({ 'ID': ['A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'B', 'B'], 'depth': [410, 415, 420, 425, 430, 435, 440, 445, 500, 505], 'value1': [10, -99, -99, -99, -99, 20, -99, 30, -99, -99], 'value2': [5, 6, -99, -99, -99, -99, 7, 8, 15, 16] }) df2 = pd.DataFrame({ 'ID': ['A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'B', 'B'], 'depth': [410, 415, 420, 425, 430, 435, 440, 445, 500, 505], 'value1': [11, 12, 13, 14, 15, 21, 22, 31, 100, 101], 'value2': [6, 7, 8, 9, 10, 11, 8, 9, 16, 17], 'value3': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] })
2. 对齐行与标记需覆盖区间
# 按ID和depth对齐两个DataFrame,保留所有行 merged = pd.merge(df1, df2, on=['ID', 'depth'], how='outer', suffixes=('_df1', '_df2')) merged = merged.sort_values(['ID', 'depth']).reset_index(drop=True) def mark_coverage_groups(group): # 标记当前行所有df1数值列是否全为-99 df1_num_cols = [col for col in merged.columns if col.endswith('_df1')] group['all_missing'] = group[df1_num_cols].apply(lambda row: all(val == -99 for val in row), axis=1) # 对连续缺失行分组 group['missing_group'] = (group['all_missing'] != group['all_missing'].shift()).cumsum() # 筛选出长度为20英尺的连续缺失分组 group_stats = group.groupby('missing_group').agg( depth_range=('depth', lambda x: x.max() - x.min()), is_missing=('all_missing', 'first') ).reset_index() valid_groups = group_stats[(group_stats['is_missing']) & (group_stats['depth_range'] == 20)] # 标记需要覆盖的行 group['need_cover'] = group['missing_group'].isin(valid_groups['missing_group']) return group # 按ID分组执行标记逻辑 merged = merged.groupby('ID').apply(mark_coverage_groups).reset_index(drop=True)
3. 执行覆盖与合并最终列
# 提取所有唯一列名(去除后缀) all_raw_cols = set(col.replace('_df1', '').replace('_df2', '') for col in merged.columns if '_df1' in col or '_df2' in col) final_df = pd.DataFrame() final_df[['ID', 'depth']] = merged[['ID', 'depth']] # 逐列合并:优先df1,符合条件时用df2覆盖,df1无的列直接取df2 for col in all_raw_cols: df1_col = f"{col}_df1" df2_col = f"{col}_df2" if df1_col in merged.columns: final_df[col] = np.where(merged['need_cover'], merged[df2_col], merged[df1_col]) else: final_df[col] = merged[df2_col] # 填充可能的空值(按需调整,比如替换为-99) final_df = final_df.fillna(-99)
4. 查看结果
print(final_df)
关键细节说明
- 多数值列兼容:自动识别所有df1的数值列,仅当整行所有数值列全为-99时,才判定为缺失行
- 区间精度:通过计算连续缺失分组的深度差判断是否为20英尺,适配5英尺间隔的子区间规则
- 列差异处理:无需提前指定列名,自动合并两个DataFrame的所有列,保证df1数据优先级
内容的提问来源于stack exchange,提问作者Celeste Wilson
相关产品推荐
相关产品推荐

