自学教程 学编程从这里开始

Pandas 重复数据处理

承接《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"(默认):第一次出现不算重复,后面重复标记True
  • keep="last":最后一次出现不算重复,前面重复标记True
  • keep=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()

九、高频坑清单

  1. 忘记设置 subset,默认整行匹配,达不到按业务主键去重的效果
  2. keep="first" 和 keep="last" 混淆,时序数据没排序就去重,保留的不是最新记录
  3. drop_duplicates 之后索引不连续,后续合并、筛选出错,记得 ignore_index=True
  4. keep=False 适合核查,不适合直接用来去重
  5. 浮点数判断重复:精度问题,两个看起来一样的浮点数会判定不重复,建议先round再去重
  6. NaN:duplicated 认为 NaN == NaN,多个NaN会判定为重复
  7. 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 条笔记