如何高效从Pandas的df2中筛选与df1指定列不匹配的行生成df3
问题描述
现有两个Pandas DataFrame df1 和 df2,定义如下:
import pandas as pd df1 = pd.DataFrame({'num': [0, 2, 3, 4, 5, 7, 9], 'lower': ['a', 'b', 'd', 'c', 'f', 'f', 'j'], 'char': ['!', '(', '$', '+', '^', '^', ')'], 'upper': ['Z', 'Y', 'X', 'W', 'V', 'U', 'T']}) df2 = pd.DataFrame({'num': range(0,10), 'lower': ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'], 'char': ['!', '@', '#', '$', '%', '^', '&', '*', '(', ')'], 'upper': ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J']})
需要生成df3,要求包含df2中在num、lower、char三列上均不与df1任意行匹配的行,upper列不参与筛选但需保留在结果中。
原实现通过嵌套遍历itertuples()找出匹配行的索引,再筛选df2中不在该索引列表的行,代码如下:
commonEntries = [] for row in df1.itertuples(): for line in df2.itertuples(): if row[df1.columns.get_loc('num')+1] == line[df2.columns.get_loc('num')+1] and row[df1.columns.get_loc('lower')+1] == line[df2.columns.get_loc('lower')+1] and row[df1.columns.get_loc('char')+1] == line[df2.columns.get_loc('char')+1]: commonEntries.append(line[0]) goodGuys = [x for x in df2.index if x not in commonEntries] goodEntries = df2.loc[goodGuys]
该方法在处理大数据量时效率极低,希望找到基于concat、join或merge等Pandas原生高效操作的解决方案。
高效解决方案
以下几种方法均利用Pandas的向量化操作替代循环,大幅提升处理效率:
方法1:使用merge结合indicator参数
通过合并两个DataFrame,利用indicator标记行的来源,筛选出仅存在于df2的行:
# 仅合并用于匹配的三列,保留df2的所有列 merged = df2.merge(df1[['num', 'lower', 'char']], on=['num', 'lower', 'char'], how='left', indicator=True) # 筛选仅来自df2的行,去掉indicator列 df3 = merged[merged['_merge'] == 'left_only'].drop('_merge', axis=1)
方法2:使用isin结合元组
将df1的匹配列转换为元组集合,利用isin快速判断df2的行是否匹配:
# 提取df1中用于匹配的三列组成元组集合 match_set = set(df1[['num', 'lower', 'char']].itertuples(index=False)) # 筛选df2中不在匹配集合的行 df3 = df2[~df2[['num', 'lower', 'char']].itertuples(index=False).isin(match_set)]
方法3:使用concat结合drop_duplicates
将两个DataFrame的匹配列合并后去重,找出仅属于df2的行:
# 合并两个DataFrame的匹配列,添加来源标记 temp = pd.concat([ df1[['num', 'lower', 'char']].assign(source='df1'), df2[['num', 'lower', 'char']].assign(source='df2') ]) # 找出仅在df2中出现的匹配组合 unique_to_df2 = temp.drop_duplicates(subset=['num', 'lower', 'char'], keep=False) unique_to_df2 = unique_to_df2[unique_to_df2['source'] == 'df2'] # 从df2中筛选出符合条件的行 df3 = df2.merge(unique_to_df2[['num', 'lower', 'char']], on=['num', 'lower', 'char'])
内容的提问来源于stack exchange,提问作者BigHeadEd
相关产品推荐
相关产品推荐

