如何在 Pandas 中按行识别并提取重复值

本文介绍如何使用 `pandas.dataframe.apply()` 配合自定义逻辑,高效实现**逐行检测重复值**,并以字符串或集合形式返回每行中出现频次大于 1 的所有元素。

在 Pandas 中,默认的 duplicated() 方法作用于列(即纵向),常用于标记或筛选列方向上的重复行;但当需求变为横向识别每行内部的重复值(例如:某一行中 "bar" 出现两次,则提

取 "bar"),就需要转向 apply(axis=1) 的行级操作。

核心思路是:对每一行(Series 对象),统计各元素出现次数,筛选出频次 > 1 的值,并去重汇总。以下是推荐的实现方式:

import pandas as pd

df2 = pd.DataFrame({
    "A": ["foo", "foo", "foo", "bar"],
    "B": [0, 1, 1, 1],
    "C": ["A", "foo", "B", "bar"],
    "D": ["bar", "bar", "B", "foo"],
    "E": ["bar", "bar", "B", "foo"]
})

# ✅ 推荐方案:返回 set(自动去重 + 无序),语义清晰且性能合理
df2["dup"] = df2.apply(
    lambda row: {val for val in row if row.tolist().count(val) > 1},
    axis=1
)

输出结果为:

     A  B    C    D    E         dup
0  foo  0    A  bar  bar       {bar}
1  foo  1  foo  bar  bar  {foo, bar}
2  foo  1    B    B    B         {B}
3  bar  1  bar  foo  foo  {foo, bar}

如需与示例中一致的逗号分隔字符串格式(如 "foo, bar"),可进一步转换:

df2["dup"] = df2["dup"].apply(lambda s: ", ".join(sorted(map(str, s))) if s else "")

⚠️ 注意事项:

  • row.tolist().count(val) 在大数据集上效率较低(时间复杂度 O(n²)),若处理超万行数据,建议改用 collections.Counter 优化:
    from collections import Counter
    df2["dup"] = df2.apply(
        lambda row: {val for val, cnt in Counter(row).items() if cnt > 1},
        axis=1
    )
  • 混合数据类型(如 int 和 str)时,Counter 更健壮;而 == 比较在 NaN 存在时需额外处理(NaN != NaN),如含缺失值,建议先用 row.fillna("MISSING") 统一占位。
  • 若需保留首次出现顺序,可用 dict.fromkeys(...) 去重后转 list,再过滤。

该方法灵活、可读性强,适用于探索性分析及清洗阶段的行级模式识别任务。