为何Merge()未执行内连接,返回数据与原DataFrame一致?
问题:合并DataFrame无法正确识别需禁用的用户
我在处理健康数据时需要自动化合并文件:对比新用户数据集ef_in和系统现有用户数据集ul_in,找出ul_in中不在ef_in内的用户并标记为禁用。但当前合并逻辑输出始终和内连接的DataFrame内容一致,程序无报错但功能失效,相关代码如下:
现有合并逻辑代码
def client_merge(ef_in, ul_in): # ef_in = pd. read_csv("COC_Ready_EF.csv", sep=',') # ul_in = pd.read_csv("Ready UserList.csv", sep=',') pd.set_option('mode.chained_assignment', None) ef_in['UniqueID'] = ef_in['UniqueID'].astype(object) ef_in['ZipCode'] = ef_in['ZipCode'].astype(object) ef_in['HireDate'] = ef_in['HireDate'].astype(object) ef_in['DateOfBirth'] = ef_in['DateOfBirth'].astype(object) ul_in['UniqueID'] = ul_in['UniqueID'].astype(object) ul_in['Action'] = ul_in['Action'].astype(object) ul_in['ZipCode'] = ul_in['ZipCode'].astype(object) df = pd.concat(([ef_in, ul_in]), axis=0, ignore_index=True, sort=False) df.drop_duplicates(subset=['UniqueID'], keep=False, inplace=True) new_users = df.merge(ef_in) disable_users = df.merge(ul_in) disable_users['Action'].fillna('Disable', inplace=True) ready_to_print_file = pd.concat([new_users, disable_users], ignore_index=False) rtpf1 = ready_to_print_file[ready_to_print_file["FirstName"].str.contains("Admin") == False] rtpf2 = rtpf1[rtpf1["FirstName"].str.contains("Clarks") == False] rtpf3 = rtpf2[rtpf2["FirstName"].str.contains("Test") == False] rtpf3.to_csv(path, header=True, index=False)
数据集格式化代码
ul_in格式化函数
def client_ul_formatter(in_file): pd.set_option('mode.chained_assignment', None) in_file = pd.read_csv(in_file, sep=',') df = in_file[['FirstName', 'LastName', 'Region', 'UniqueID', 'DateOfBirth', 'Gender', 'ZipCode', 'Email', 'Role', 'HireDate', 'Company', 'Action']] return df
ef_in格式化函数
def rotate_date(strg, n): return strg[n:] + strg[:n] def client_ef_formatter(input_file): pd.set_option('mode.chained_assignment', None) input_file = pd.read_csv(input_file, sep=',', dtype={'HIREDATE': str, 'DATE OF BIRTH': str}) df = input_file[['LAST NAME', 'FIRST AND MIDDLE', 'DATE OF BIRTH', 'GENDER', 'RELATIONSHIP', 'HIREDATE', 'ZIP', 'ALT ID', 'EMAIL ADDRESS']] df = df.drop(df[df['RELATIONSHIP'] != 'E'].index) df = df.drop(['RELATIONSHIP'], axis=1) p = -1 hdf = [] for _ in (df['HIREDATE']): p = (p + len(df['HIREDATE']) - (len(df['HIREDATE']) - 1)) hd = df['HIREDATE'].iloc[p] f = rotate_date(hd, -4) hdf.append(f) q = -1 ddf = [] for _ in (df['DATE OF BIRTH']): q = (q + len(df['DATE OF BIRTH']) - (len(df['DATE OF BIRTH']) - 1)) dob = df['DATE OF BIRTH'].iloc[q] f = rotate_date(dob, -4) ddf.append(f) df['HIREDATE'] = hdf df['DATE OF BIRTH'] = ddf df['DATE OF BIRTH'] = pd.to_datetime(df['DATE OF BIRTH'], errors='coerce', format='%m%d%Y') df['HIREDATE'] = pd.to_datetime(df['HIREDATE'], errors='coerce', format='%m%d%Y') df.rename(columns={'HIREDATE': 'HireDate', 'LAST NAME': 'LastName', 'FIRST AND MIDDLE': 'FirstName', 'DATE OF BIRTH': 'DateOfBirth', 'ALT ID': 'UniqueID', 'GENDER': 'Gender', 'ZIP': 'ZipCode', 'EMAIL ADDRESS': 'Email'}, inplace=True) df['Region'] = pd.Series(dtype=str) df['Role'] = pd.Series(dtype=str) df['Company'] = pd.Series(dtype=str) df['Action'] = pd.Series(dtype=str) df = df.reindex(columns=['FirstName', 'LastName', 'Region', 'UniqueID', 'DateOfBirth', 'Gender', 'ZipCode', 'Email', 'Role', 'HireDate', 'Company', 'Action']) df['Company'].fillna('client_account', inplace=True) df['Role'].fillna('Employee On Plan', inplace=True) df.to_csv(path, header=True, index=False)
问题根源
- 合并逻辑绕路且易出错:先concat再去重的方式,会因为
UniqueID之外的列值差异(比如日期格式、空格),导致无法正确筛选出两边独有的用户;后续的内连接merge会进一步因为列值不匹配丢失数据。 - 类型处理矛盾:
client_ef_formatter中将日期转为datetime类型后,client_merge又转回object,容易引发格式不一致导致匹配失败。 - 过滤代码冗余:多次重复的
str.contains判断可以简化。
修复后的合并逻辑
def client_merge(ef_in, ul_in): pd.set_option('mode.chained_assignment', None) # 统一UniqueID为字符串并去除首尾空格,避免类型/空格导致的匹配失败 ef_in['UniqueID'] = ef_in['UniqueID'].astype(str).str.strip() ul_in['UniqueID'] = ul_in['UniqueID'].astype(str).str.strip() # 直接筛选ul_in中不在ef_in的用户,标记为禁用 disable_users = ul_in[~ul_in['UniqueID'].isin(ef_in['UniqueID'])].copy() disable_users['Action'] = 'Disable' # 筛选ef_in中不在ul_in的新用户(可选:标记新增动作) new_users = ef_in[~ef_in['UniqueID'].isin(ul_in['UniqueID'])].copy() new_users['Action'] = new_users['Action'].fillna('Add') # 合并结果 ready_to_print_file = pd.concat([new_users, disable_users], ignore_index=True) # 一次性过滤所有测试/管理员账号 rtpf = ready_to_print_file[ ~ready_to_print_file["FirstName"].str.contains("Admin|Clarks|Test", case=False) ] rtpf.to_csv(path, header=True, index=False)
修复说明
- 简化匹配逻辑:用
isin直接筛选两边独有的用户,避免concat+去重+merge的复杂流程,逻辑更清晰可靠。 - 统一ID格式:将
UniqueID转为字符串并去空格,彻底解决类型或空格导致的匹配失效问题。 - 明确动作标记:直接给禁用用户赋值
Action='Disable',避免fillna带来的不确定性。 - 优化过滤代码:用正则表达式一次性过滤所有不需要的关键词,减少冗余代码。
内容的提问来源于stack exchange,提问作者Pongotan
相关产品推荐
相关产品推荐

