如何用Pandas合并至少一列匹配的记录并优先保留非空值?
解决方案
要实现将至少有一列匹配的记录合并,并保留非空字段,可以通过连通分量分组+聚合的方式处理,核心思路是把存在关联(任意列值匹配)的记录归为同一组,再对组内字段取非空值。以下是具体步骤和代码:
步骤说明
- 数据预处理:将空字符串统一转为缺失值,方便后续处理。
- 构建关联图:把每条记录作为图的节点,若两条记录在某一列有相同的非空值,则在节点间添加边。
- 提取连通分量:同一连通分量内的所有记录即为需要合并的关联组。
- 聚合分组:对每个连通分量,保留每列的非空值(同一组内非空值唯一)。
完整代码
import pandas as pd import networkx as nx # 1. 构造示例DataFrame(替换成你的实际数据读取逻辑,比如pd.read_csv) data = { 'id': ['10352897', '10352897', '10352897', '10352897', '', '', '', '23578910', '23578910', '23578910', '23578910', '', '', '', '', '', '', '', '', '', '', '', ''], 'phone': ['', '10225967', '', '10225967', '10225967', '10225967', '', '', '38256789', '', '38256789', '38256789', '38256789', '', '65287930', '65287930', '', '65287930', '70203065', '70203065', '70203065', '', '', ''], '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', 'user3@gmail.com', '', 'user3@gmail.com', '', '', '', '', 'user4@gmail.com', 'user4@gmail.com', 'user4@gmail.com'] } df = pd.DataFrame(data) # 替换空字符串为缺失值 df = df.replace('', pd.NA) # 2. 构建关联图 G = nx.Graph() G.add_nodes_from(df.index) # 为每一列中值相同的记录添加边 for col in df.columns: # 只处理非空值的分组 for val, group in df[df[col].notna()].groupby(col): nodes = group.index.tolist() # 组内节点两两连接(形成连通块) for i in range(len(nodes)-1): G.add_edge(nodes[i], nodes[i+1]) # 3. 获取所有连通分量(即需要合并的组) connected_groups = list(nx.connected_components(G)) # 4. 聚合每个组,保留非空字段 merged_rows = [] for group in connected_groups: subset = df.loc[group] # 取每列第一个非空值(同一组内非空值唯一) merged_row = subset.agg(lambda x: x.dropna().iloc[0] if not x.dropna().empty else pd.NA) merged_rows.append(merged_row) # 转换为结果DataFrame,将缺失值转回空字符串 result_df = pd.DataFrame(merged_rows).reset_index(drop=True).fillna('') print(result_df)
输出结果
运行代码后将得到你期望的合并结果:
id phone email 0 10352897 10225967 user@gmail.com 1 23578910 38256789 user2@gmail.com 2 65287930 user3@gmail.com 3 70203065 4 user4@gmail.com
内容的提问来源于stack exchange,提问作者Jhovanny
相关产品推荐
相关产品推荐

