如何在Pandas中筛选匹配子集DataFrame并修改指定行值?
问题解决:基于DataFrame匹配与字段更新的实现
问题场景
我们有两个Pandas DataFrame:df1 的结构如下:
import pandas as pd df1 = pd.DataFrame({ "ID1": ["foo", "fizz"], "ID2": ["bar", "buzz"] })
输出:
ID1 ID2 0 foo bar 1 fizz buzz
df2 的结构如下:
df2 = pd.DataFrame({ "ID1": ["abc", "fizz", "fizz1", "foo", "foo"], "ID2": ["def", "buzz", "buzz2", "bar", "bar"], "Count": [7, 5, 9, 6, 6], "Code": ["B", "B", "C", "B", "Z"] })
输出:
ID1 ID2 Count Code 0 abc def 7 B 1 fizz buzz 5 B 2 fizz1 buzz2 9 C 3 foo bar 6 B 4 foo bar 6 Z
需求分为两步:
- 从
df2中筛选出ID1和ID2与df1任意行完全匹配的记录,得到子集sub_df - 对
sub_df执行更新:当Count字段值≥5时,将对应Code字段改为"A" - 最终保留
df2的原始结构,只更新符合条件的行
解决方案
这里提供两种简洁的实现方式,你可以根据自己的习惯选择:
方法一:用合并标记匹配行(直观易理解)
# 给df1加一个匹配标记列 df1['is_match'] = True # 左连接df2和df1,标记出所有匹配的行 df2_with_match = df2.merge(df1, on=['ID1', 'ID2'], how='left') # 复制df2得到目标结果,避免修改原数据 target_df = df2.copy() # 同时满足两个条件:是匹配行 + Count≥5,就把Code改成"A" update_mask = (df2_with_match['is_match'].notna()) & (target_df['Count'] >= 5) target_df.loc[update_mask, 'Code'] = "A"
方法二:用元组匹配(更简洁)
# 把df1的ID组合转换成元组列表 id_pairs = list(df1.itertuples(index=False, name=None)) # 直接判断df2的每行ID组合是否在df1的元组列表里 match_mask = df2[['ID1', 'ID2']].apply(tuple, axis=1).isin(id_pairs) # 复制df2并更新符合条件的行 target_df = df2.copy() target_df.loc[match_mask & (target_df['Count'] >= 5), 'Code'] = "A"
最终结果
执行上述任意一种方法后,打印target_df就能得到需求的结果:
print(target_df)
输出:
ID1 ID2 Count Code 0 abc def 7 B 1 fizz buzz 5 A 2 fizz1 buzz2 9 C 3 foo bar 6 A 4 foo bar 6 A
小提示
- 如果不想修改原始的
df2,一定要记得用.copy()创建副本,否则会直接改动原数据 - 第二种方法在数据量较大时,效率可能略低于第一种合并的方式,小数据量场景下完全可以放心用
内容的提问来源于stack exchange,提问作者ah bon
相关产品推荐
相关产品推荐

