如何基于至少一列匹配合并Pandas DataFrame记录并保留非空字段?
合并DataFrame中关联记录(优先保留非空字段)
你需要合并存在至少一列匹配的记录,优先保留已填充的非空字段,最终得到每个唯一组的完整记录。以下是基于pandas的实现方案:
步骤1:导入依赖并构造DataFrame
先把原始数据转换成pandas的DataFrame,并将空字符串替换为缺失值(NaN),方便后续处理:
import pandas as pd import numpy as np # 构造原始数据 data = { 'id': ['10352897', '10352897', '10352897', '10352897', '', '', '', '23578910', '23578910', '23578910', '23578910', '', '', ''], 'phone': ['', '10225967', '', '10225967', '10225967', '10225967', '', '', '38256789', '', '38256789', '38256789', '38256789', ''], 'email': ['', '', 'user@gmail.com', 'user@gmail.com', '', 'user@gmail.com', 'user@gmail.com', '', '', 'user2@gmail.com', 'user2@gmail.com', '', 'user2@gmail.com', 'user2@gmail.com'] } df = pd.DataFrame(data) # 将空字符串转为NaN df = df.replace('', np.nan)
步骤2:合并关联记录
这里提供两种可行的方法:
方法一:分组填充缺失值后去重
通过按email、phone、id依次分组填充缺失值,确保同一组的记录都拥有完整的字段值,最后去重得到结果:
# 按email分组,填充id和phone的缺失值 df['id'] = df.groupby('email')['id'].transform(lambda x: x.bfill().ffill()) df['phone'] = df.groupby('email')['phone'].transform(lambda x: x.bfill().ffill()) # 按phone分组,填充id和email的缺失值 df['id'] = df.groupby('phone')['id'].transform(lambda x: x.bfill().ffill()) df['email'] = df.groupby('phone')['email'].transform(lambda x: x.bfill().ffill()) # 按id分组,填充phone和email的缺失值 df['phone'] = df.groupby('id')['phone'].transform(lambda x: x.bfill().ffill()) df['email'] = df.groupby('id')['email'].transform(lambda x: x.bfill().ffill()) # 去重并重置索引 result = df.drop_duplicates().reset_index(drop=True)
方法二:基于分组键聚合
为每条记录生成分组键(优先使用id,其次phone,最后email),然后按分组键聚合,取每个字段的第一个非空值:
# 生成分组键 def get_group_key(row): if pd.notna(row['id']): return row['id'] elif pd.notna(row['phone']): return row['phone'] else: return row['email'] df['group_key'] = df.apply(get_group_key, axis=1) # 分组聚合,提取每个字段的非空值 result = df.groupby('group_key').agg( id=('id', lambda x: x.dropna().iloc[0]), phone=('phone', lambda x: x.dropna().iloc[0]), email=('email', lambda x: x.dropna().iloc[0]) ).reset_index(drop=True)
最终输出
执行上述代码后,result就是你需要的结果:
id phone email 0 10352897 10225967 user@gmail.com 1 23578910 38256789 user2@gmail.com
内容的提问来源于stack exchange,提问作者Jhovanny
相关产品推荐
相关产品推荐

