承接《Pandas 时间序列分析》,本篇讲解 Pandas 重复数据识别、查看、去重、保留策略、标记重复行、部分字段去重、分组去重、重复数据统计,是数据清洗里非常高频的模块,保持系列教程统一风格。
前置导入与示例数据
import pandas as pd
import numpy as np
df = pd.DataFrame({
"name": ["张三", "李四", "张三", "王五", "李四", "张三", "赵六"],
"age": [22, 25, 22, 30, 25, 24, 28],
"city": ["杭州", "上海", "杭州", "北京", "上海", "杭州", "广州"],
"salary": [8000, 12000, 8000, 15000, 12000, 9000, 11000]
})
print(df)
一、核心API说明
duplicated():标记重复行,返回布尔Series,判断哪些行是重复的drop_duplicates():删除重复行,返回去重后的DataFrame- 参数通用:
subset、keep
二、duplicated() 查找重复行
默认:整行全部字段相同才判定重复,保留第一次出现的,后面重复标记为True
df["is_dup"] = df.duplicated()
print(df[df["is_dup"]])
参数 keep
keep="first"(默认):第一次出现不算重复,后面重复标记Truekeep="last":最后一次出现不算重复,前面重复标记Truekeep=False:所有重复的行全部标记True(非常适合找出全部重复记录)
# 把所有重复记录全部筛选出来
dup_all = df[df.duplicated(keep=False)]
print(dup_all)
subset:指定部分字段判定重复(业务最常用)
只根据 name + city 判断是否重复,忽略age、salary
df["is_dup_name_city"] = df.duplicated(subset=["name","city"], keep=False)
print(df[df["is_dup_name_city"]])
三、drop_duplicates() 去重
基础语法
df.drop_duplicates(subset=None, keep="first", inplace=False, ignore_index=False)
inplace=True:原地修改原表(不推荐,建议赋值新变量)ignore_index=True:去重之后,重置行索引,索引连续
示例1:整行去重,保留首次
df1 = df.drop_duplicates()
示例2:按指定字段去重,保留最后一条
# 同一个name+city,保留最后一条记录
df2 = df.drop_duplicates(subset=["name","city"], keep="last")
示例3:去重后重置索引
df3 = df.drop_duplicates(subset=["name"], keep="first", ignore_index=True)
四、统计重复数量
# 总重复行数
dup_count = df.duplicated().sum()
print(f"重复行数:{dup_count}")
# 按关键字段统计重复频次
df[["name","city"]].value_counts()
五、分组去重(复杂场景)
很多场景需要分组内去重,或者分组内按规则保留一条(比如保留薪资最高的一条)
# 同name只保留薪资最高的一行
df4 = df.loc[df.groupby("name")["salary"].idxmax()]
print(df4)
这种方式不是 drop_duplicates,是分组取极值,适合:不是简单按先后保留,按业务规则选一条
六、重复数据标记 + 导出核查
清洗的时候经常需要打标记,把重复行单独导出核对,而不是直接删掉
df["dup_flag"] = df.duplicated(subset=["name","city"], keep=False)
# 导出重复数据单独核查
dup_df = df[df["dup_flag"]]
# dup_df.to_excel("重复数据核查.xlsx", index=False)
七、时序场景去重(订单、日志)
日志经常会出现同一主键多条重复上报,一般保留最新时间
df_order = pd.DataFrame({
"order_id": ["o01","o02","o01","o03","o02"],
"dt": pd.to_datetime(["2025-01-01 08:10","2025-01-01 08:12","2025-01-01 08:15","2025-01-01 08:20","2025-01-01 08:14"]),
"amount": [100,200,100,300,200]
})
# 同一个order_id保留时间最晚的一条
df_order = df_order.sort_values("dt").drop_duplicates(subset=["order_id"], keep="last")
print(df_order)
八、和 set / unique 的区别
duplicated / drop_duplicates:面向整张DataFrame,支持多字段组合判断Series.unique():只看单列,获取该列唯一值数组
df["name"].unique()
九、高频坑清单
- 忘记设置
subset,默认整行匹配,达不到按业务主键去重的效果 keep="first"和keep="last"混淆,时序数据没排序就去重,保留的不是最新记录- drop_duplicates 之后索引不连续,后续合并、筛选出错,记得
ignore_index=True keep=False适合核查,不适合直接用来去重- 浮点数判断重复:精度问题,两个看起来一样的浮点数会判定不重复,建议先round再去重
- NaN:duplicated 认为 NaN == NaN,多个NaN会判定为重复
- inplace=True 直接修改原数据,一旦删错无法恢复,优先新变量接收
十、综合实战模板
def deduplicate_data(df, dup_cols, keep_rule="last"):
"""
通用去重函数
:param df: 原始DataFrame
:param dup_cols: 判定重复的字段列表
:param keep_rule: first / last
:return: 去重后的数据
"""
df_clean = df.drop_duplicates(subset=dup_cols, keep=keep_rule, ignore_index=True)
return df_clean
def find_all_dup_rows(df, dup_cols):
"""找出全部重复记录,用于人工核查"""
flag = df.duplicated(subset=dup_cols, keep=False)
return df[flag].sort_values(dup_cols)
# 使用示例
dup_check = find_all_dup_rows(df, ["name","city"])
df_clean = deduplicate_data(df, ["name","city"], keep_rule="last")
print("【待核查重复数据】")
print(dup_check)
print("【去重后数据】")
print(df_clean)
十一、速查表
| 需求 | 写法 |
|---|---|
| 查看哪些行是重复 | df.duplicated() |
| 找出所有重复记录(全部标记True) | df.duplicated(keep=False) |
| 按指定字段去重 | drop_duplicates(subset=[col1,col2]) |
| 保留最新一条(时序) | sort_values + drop_duplicates(keep=”last”) |
| 分组内按指标择优保留 | groupby + idxmax / idxmin |
0 条笔记