Pandas df.drop_duplicates()无效,浮点精度致重复行无法删除
Pandas drop_duplicates 无效:浮点数精度导致的"伪重复"问题
这是典型的浮点数精度误差问题——虽然表面显示都是3542.87,但实际存储的是带有微小尾差的浮点值(比如3542.87、3542.8700000000003、3542.870000000001),这些差异肉眼不可见,但会让drop_duplicates()判定为不同行。
一、现有数据的清理方案
1. 四舍五入到指定小数位
针对金额数据,直接保留两位小数即可解决问题:
# 对solde列四舍五入到两位小数 df['solde'] = df['solde'].round(2) # 执行去重 df_cleaned = df.drop_duplicates(subset=['Date', 'Libellé', 'Montant', 'solde'], keep='first')
2. 模糊匹配去重(自定义精度)
如果需要更灵活的误差范围控制,用numpy.isclose实现模糊分组:
import numpy as np def merge_close_solde(group): # 以组内第一个solde值为基准,将所有接近的数值统一 base_val = group['solde'].iloc[0] group['solde'] = np.where(np.isclose(group['solde'], base_val, atol=1e-6), base_val, group['solde']) return group # 分组统一数值后再去重 df_cleaned = df.groupby(['Date', 'Libellé', 'Montant'], group_keys=False).apply(merge_close_solde) df_cleaned = df_cleaned.drop_duplicates()
3. 用Decimal类型实现精确运算
如果要彻底杜绝浮点误差,将金额列转换为decimal.Decimal类型(支持精确十进制计算):
from decimal import Decimal, getcontext # 设置精度为两位小数,适配金额场景 getcontext().prec = 2 # 转换solde和Montant列 df['solde'] = df['solde'].apply(lambda x: Decimal(str(x)).quantize(Decimal('0.00'))) df['Montant'] = df['Montant'].apply(lambda x: Decimal(str(x)).quantize(Decimal('0.00'))) # 此时去重可正常执行 df_cleaned = df.drop_duplicates()
二、预防未来出现此类问题的措施
- 导入阶段处理:读取数据时直接控制精度,避免浮点误差引入:
# 读取CSV时直接对金额列四舍五入 df = pd.read_csv('your_data.csv', converters={ 'solde': lambda x: round(float(x), 2), 'Montant': lambda x: round(float(x), 2) }) - 避免运算累积误差:如果数据是计算生成的,每一步运算后都进行精度截断(比如四舍五入),防止微小误差累积放大。
- 整数存储金额:将金额转换为分(乘以100),用整数类型存储,彻底消除小数运算的精度问题:
# 转换为分存储,用Int64类型支持空值 df['solde_cents'] = (df['solde'] * 100).astype('Int64') df['Montant_cents'] = (df['Montant'] * 100).astype('Int64')
内容的提问来源于stack exchange,提问作者fran6
相关产品推荐
相关产品推荐

