如何对比DataFrame行:判断相等或df2空值转df1非空值
DataFrame行对比:特定匹配规则的实现
以下提供两种实现方式,满足你的需求:仅保留完全匹配或df2对应字段为空字符串且df1同字段非空、其余字段完全匹配的行ID,排除其他不匹配情况。
方案一:逐行转字典循环实现(小数据量友好)
逻辑直观,适合数据量不大的场景:
import pandas as pd # 构造测试数据 df1 = pd.DataFrame({ 'NAME': ['Kelly', 'Jack', 'Josh'], 'AGE': [15, 12, 30], 'CITY': ['London', '', 'Austin'], 'GENDER': ['F', 'M', 'M'], 'ID': [15, 98, 12] }) df2 = pd.DataFrame({ 'NAME': ['Kelly', 'Jack', 'Josh'], 'AGE': [15, '', 30], 'CITY': ['', 'Munich', 'Austin'], 'GENDER': ['F', 'M', 'M'], 'ID': [15, 98, 12] }) # 将DataFrame转换为以ID为键的行字典 df1_row_dict = df1.set_index('ID').to_dict('index') df2_row_dict = df2.set_index('ID').to_dict('index') result_ids = [] # 遍历所有共同ID for id_val in df1_row_dict.keys() & df2_row_dict.keys(): row1 = df1_row_dict[id_val] row2 = df2_row_dict[id_val] is_match = True # 逐字段校验匹配规则 for col in row1.keys(): val1 = row1[col] val2 = row2[col] # 不满足规则的情况:值不等,且不是df2空、df1非空的场景 if not (val1 == val2 or (val2 == '' and val1 != '')): is_match = False break if is_match: result_ids.append(id_val) print(result_ids) # 输出:[15, 12]
逻辑说明
- 先将两个DataFrame转为以ID为索引的字典,通过ID快速定位对应行
- 遍历每个共同ID,逐字段检查:
- 要么字段值完全相等
- 要么df2的字段值为空字符串,且df1的对应字段值非空
- 所有字段都满足规则时,将ID加入结果列表
方案二:Pandas矢量化操作(大数据量高效)
利用Pandas的批量运算能力,避免循环,适合处理大规模数据:
import pandas as pd # 构造测试数据(同方案一) df1 = pd.DataFrame({ 'NAME': ['Kelly', 'Jack', 'Josh'], 'AGE': [15, 12, 30], 'CITY': ['London', '', 'Austin'], 'GENDER': ['F', 'M', 'M'], 'ID': [15, 98, 12] }) df2 = pd.DataFrame({ 'NAME': ['Kelly', 'Jack', 'Josh'], 'AGE': [15, '', 30], 'CITY': ['', 'Munich', 'Austin'], 'GENDER': ['F', 'M', 'M'], 'ID': [15, 98, 12] }) # 按ID内连接两个DataFrame,对齐行数据 merged_df = pd.merge(df1, df2, on='ID', suffixes=('_df1', '_df2')) # 获取需要对比的字段(排除ID) compare_fields = [col.replace('_df1', '') for col in merged_df.columns if '_df1' in col] # 生成每个字段的匹配条件 match_conditions = [] for field in compare_fields: col_df1 = f"{field}_df1" col_df2 = f"{field}_df2" # 条件:值相等 或 df2字段为空且df1字段非空 condition = (merged_df[col_df1] == merged_df[col_df2]) | (merged_df[col_df2] == '' & merged_df[col_df1] != '') match_conditions.append(condition) # 筛选出所有字段都满足条件的行 valid_rows = pd.concat(match_conditions, axis=1).all(axis=1) # 提取符合条件的ID result_ids = merged_df.loc[valid_rows, 'ID'].tolist() print(result_ids) # 输出:[15, 12]
逻辑说明
- 使用
merge按ID对齐两个DataFrame,通过后缀区分来自不同DF的字段 - 对每一组对应字段生成匹配规则的布尔数组
- 用
all(axis=1)检查每行是否所有字段都满足规则,最终提取符合条件的ID
结果解释
测试用例中ID98被排除的原因:df2的CITY字段为Munich(非空),而df1的CITY字段为空字符串,属于「df2非空但df1为空」的不匹配场景,不符合规则,因此不加入结果。
内容的提问来源于stack exchange,提问作者Angie
相关产品推荐
相关产品推荐

