Pandas拼接DataFrame后,drop_duplicates去重失效仅删少量重复行
Pandas拼接后drop_duplicates去重失效的排查与解决
常见问题排查(按出现概率从高到低)
- 浮点数精度差(80%以上的同类问题根源)
肉眼看起来完全一致的Value数值,实际因为计算、存储的精度问题存在微小差异:比如经过浮点运算后产生的1.23456789和1.23456788,因为pandas默认显示会截断小数位,肉眼根本看不出区别,但比对时会被判定为两个完全不同的值,自然不会触发去重逻辑。
验证方法:直接取你认为重复的两行的Value值,打印全精度并计算差值:
如果差值不是0,就是精度问题。解决方式是按照业务要求的最小精度,去重前把两个DataFrame的Value统一做四舍五入,消掉无意义的误差:# 替换成你判定重复行的实际索引 val1 = df_q.loc[对应行索引, 'Value'] val2 = df_q_temp.loc[对应行索引, 'Value'] print("全精度值1:", val1) print("全精度值2:", val2) print("两值绝对差:", abs(val1 - val2))# 比如业务要求保留6位小数,按实际精度调整 df_q['Value'] = df_q['Value'].round(6) df_q_temp['Value'] = df_q['Value'].round(6) - Date列的类型或粒度不统一
这是第二高发的问题,常见的坑有两个:- 两个DataFrame的Date列数据类型不一致:比如一个是datetime类型,一个是纯字符串,哪怕显示的文本完全一样,pandas也会判定为不同值;如果Date列带时区、或者存在时分秒毫秒的粒度差异,打印时只显示日期部分,就会看起来一致,实际值根本不相等。
- 人为把Date的匹配粒度设得太粗,会导致有效行被误删:比如业务上本来需要区分同一天不同小时的数值,硬把Date转成只保留到日期的格式,自然会把不同时间的有效行判定为重复,出现过度删除的问题。
验证方法:逐值打印Date的类型和精确内容:
解决方式:去重前把两个DataFrame的Date列统一转成相同的类型,按业务需要的粒度对齐截断:date1 = df_q.loc[对应行索引, 'Date'] date2 = df_q_temp.loc[对应行索引, 'Date'] print("df_q的Date类型:", type(date1), "精确值:", date1) print("df_q_temp的Date类型:", type(date2), "精确值:", date2)# 统一转成datetime类型,按小时对齐,根据实际业务调整对齐粒度 df_q['Date'] = pd.to_datetime(df_q['Date']).dt.floor('h') df_q_temp['Date'] = pd.to_datetime(df_q_temp['Date']).dt.floor('h') - 字段存在不可见的隐性差异
如果Date是从字符串转来的,可能存在前后空格、不可见的特殊字符,哪怕肉眼看起来文本完全一样,也会被判定为不同值。
验证方法:逐列直接用==比对疑似重复的两个值:for col in ['Date', 'Value']: v1 = df_q.loc[对应行索引, col] v2 = df_q_temp.loc[对应行索引, col] print(f"{col}列两值是否相等:{v1 == v2}")
可直接复用的标准化去重代码
先对两个源DataFrame做字段标准化处理,再执行拼接去重,从根源上避免因为源数据的隐式差异导致去重结果异常:
# 拷贝原数据避免修改原始数据 df_q_std = df_q.copy() df_q_temp_std = df_q_temp.copy() # 统一Date格式和粒度 df_q_std['Date'] = pd.to_datetime(df_q_std['Date']).dt.floor('h') df_q_temp_std['Date'] = pd.to_datetime(df_q_temp_std['Date']).dt.floor('h') # 统一Value精度 df_q_std['Value'] = df_q_std['Value'].round(6) df_q_temp_std['Value'] = df_q_temp_std['Value'].round(6) # 拼接后按业务指定列去重 bigdata = pd.concat([df_q_std, df_q_temp_std]).drop_duplicates( subset=['Date', 'Value'], keep='first' ).reset_index(drop=True)
注意:round的小数位数、Date的对齐粒度必须匹配业务的实际要求,精度设置过粗会把本来不同的有效行判定为重复,造成过度删除。
内容的提问来源于stack exchange,提问作者S. AG
相关产品推荐
相关产品推荐

