基于Python实现Vlookup匹配及不匹配原因排查的代码优化问询
问题分析与代码优化方案
原代码核心问题
- 拼接列引用错误:代码中出现
df2_of01['Date']、df2_Name['Date']这类笔误,引用了不存在的DataFrame,导致拼接结果完全错误。 - 字段匹配逻辑混乱:
- Date匹配判断时,用
df2_B.loc[df2_B['B_Concate'] == row['A_Concate'], 'Date']筛选,而整体不匹配时该结果为空,会错误返回Not match date。 - Quantity匹配逻辑存在未定义变量(
Match part?、SUGGESTED QTY),且未结合Name/Date的关联关系判断,忽略了一对多数据场景。
- Date匹配判断时,用
- 数据格式未统一:Date的字符串格式、Quantity的类型转换不一致,可能导致本该匹配的记录因格式差异被误判为不匹配。
优化后的完整代码
import pandas as pd import numpy as np # 1. 复制数据并统一字段格式,修正拼接逻辑 df2_A = df1_A.copy() df2_B = df1_B.copy() # 统一处理Date格式(避免datetime转字符串时的格式差异) df2_A['Date_str'] = pd.to_datetime(df2_A['Date']).dt.strftime('%Y-%m-%d') df2_B['Date_str'] = pd.to_datetime(df2_B['Date']).dt.strftime('%Y-%m-%d') # 统一Quantity类型(转int后再转字符串,避免float类型的.0后缀) df2_A['Quantity_str'] = df2_A['Quantity'].astype(int).astype(str) df2_B['Quantity_str'] = df2_B['Quantity'].astype(int).astype(str) # 生成拼接列 df2_A['A_Concate'] = df2_A['Name'] + df2_A['Date_str'] + df2_A['Quantity_str'] df2_B['B_Concate'] = df2_B['Name'] + df2_B['Date_str'] + df2_B['Quantity_str'] # 2. 整体匹配判断 df2_A['Match with B?'] = df2_A['A_Concate'].isin(df2_B['B_Concate']).map({True: 'Yes', False: 'No'}) # 3. 预处理B的数据,创建快速查询映射(适配一对多/多对多关系) B_name_set = set(df2_B['Name'].unique()) # 每个Name对应的所有Date集合 B_name_to_dates = df2_B.groupby('Name')['Date_str'].apply(set).to_dict() # 每个(Name, Date)对应的所有Quantity集合 B_name_date_to_qtys = df2_B.groupby(['Name', 'Date_str'])['Quantity_str'].apply(set).to_dict() # 4. 按优先级判断各字段匹配状态 # 判断Name匹配情况 df2_A['Match name?'] = np.where( df2_A['Match with B?'] == 'Yes', 'Match name', np.where(df2_A['Name'].isin(B_name_set), 'Match name', 'Not match name') ) # 判断Date匹配情况(仅当Name匹配时才检查) df2_A['Match date?'] = np.where( df2_A['Match with B?'] == 'Yes', 'Match date', np.where( df2_A['Match name?'] == 'Not match name', 'Match date', # Name已不匹配,Date是否匹配不影响核心原因 df2_A.apply(lambda row: 'Match date' if row['Date_str'] in B_name_to_dates.get(row['Name'], set()) else 'Not match date', axis=1) ) ) # 判断Quantity匹配情况(仅当Name和Date都匹配时才检查) df2_A['Match quantity?'] = np.where( df2_A['Match with B?'] == 'Yes', 'Match quantity', np.where( df2_A['Match name?'] == 'Not match name', 'Match quantity', np.where( df2_A['Match date?'] == 'Not match date', 'Match quantity', df2_A.apply(lambda row: 'Match quantity' if row['Quantity_str'] in B_name_date_to_qtys.get((row['Name'], row['Date_str']), set()) else 'Not match quantity', axis=1) ) ) ) # 清理临时辅助列 df2_A.drop(columns=['Date_str', 'Quantity_str'], inplace=True) df2_B.drop(columns=['Date_str', 'Quantity_str'], inplace=True)
关键优化点说明
- 统一数据格式:将Date转为固定格式的字符串,Quantity统一转int后再转字符串,彻底避免因格式/类型差异导致的无效不匹配。
- 预处理映射表:通过分组创建Name→Date、(Name,Date)→Quantity的集合映射,利用集合O(1)的查询效率,适配一对多/多对多的数据场景,避免逐行全表扫描。
- 明确逻辑优先级:按照Name→Date→Quantity的顺序判断,只有前一个字段匹配时才检查下一个字段,符合整体不匹配的原因排查逻辑。
- 向量化+按需apply:优先使用
np.where做向量化判断,仅在需要关联映射表时使用apply,平衡代码可读性与执行效率。 - 边界情况处理:当Name已不匹配时,直接标记Date和Quantity为匹配(因为核心不匹配原因是Name),避免误判。
内容的提问来源于stack exchange,提问作者Est
相关产品推荐
相关产品推荐

