You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Pandas DataFrame中删除最少行,使两列值均唯一?

问题:保留Pandas DataFrame两列唯一值且删除最少行

我在使用Pandas DataFrame时,希望删除尽可能少的行,让数据集中的两列各自都只有唯一值。本来想过用NetworkX的最大流算法,但觉得有点小题大做,想问问有没有更合适的替代方案?

我的尝试

我写了以下代码,但它删除了过多的行:

import pandas as pd

# 创建示例DataFrame
df = pd.DataFrame({'column1': [1, 2, 3, 1, 3, 4],
                   'column2': [5, 6, 7, 8, 9, 7]})

print("Original DataFrame:")
print(df)

# 尝试删除重复行的函数
def remove_duplicate_rows(df):
    # 按column1去重
    df.drop_duplicates(subset='column1', inplace=True)
    # 再按column2去重
    df.drop_duplicates(subset='column2', inplace=True)
    return df

# 应用函数
result = remove_duplicate_rows(df)

print("\nResulting DataFrame:")
print(result)

输出结果

Original DataFrame:
   column1  column2
0        1        5
1        2        6
2        3        7
3        1        8
4        3        9
5        4        7

Resulting DataFrame:
   column1  column2
0        1        5
1        2        6
2        3        7

这个结果删除了3行,但其实只需要删除2行就能满足要求,理想的输出应该是:

Resulting DataFrame:
   column1  column2
0        1        5
1        2        6
4        3        9
5        4        7

解决方案:贪心算法实现最小行删除

这个问题本质是要找到二分图的最大匹配(将两列视为二分图的两个节点集合,每行是连接两个节点的边),我们需要选出最多的边,让每个节点只出现在一条边中,这样删除的行数最少。

下面是一个轻量的贪心实现,无需依赖NetworkX:

import pandas as pd

def max_unique_subset(df, col1, col2):
    df_copy = df.copy().reset_index(drop=True)
    selected_indices = []
    used_col1 = set()
    used_col2 = set()

    # 第一步:优先保留单关联的行(某列值仅对应另一列唯一值)
    # 处理column1中唯一的行
    col1_counts = df_copy[col1].value_counts()
    unique_col1_vals = col1_counts[col1_counts == 1].index
    for val in unique_col1_vals:
        row = df_copy[df_copy[col1] == val].iloc[0]
        if row[col2] not in used_col2:
            selected_indices.append(row.name)
            used_col1.add(val)
            used_col2.add(row[col2])
    df_copy = df_copy.drop(selected_indices)

    # 处理column2中唯一的行
    col2_counts = df_copy[col2].value_counts()
    unique_col2_vals = col2_counts[col2_counts == 1].index
    new_selected = []
    for val in unique_col2_vals:
        row = df_copy[df_copy[col2] == val].iloc[0]
        if row[col1] not in used_col1:
            new_selected.append(row.name)
            used_col1.add(row[col1])
            used_col2.add(val)
    selected_indices.extend(new_selected)
    df_copy = df_copy.drop(new_selected)

    # 第二步:处理剩余冲突行,贪心选择不冲突的行
    while not df_copy.empty:
        found = False
        for idx, row in df_copy.iterrows():
            if row[col1] not in used_col1 and row[col2] not in used_col2:
                selected_indices.append(idx)
                used_col1.add(row[col1])
                used_col2.add(row[col2])
                df_copy = df_copy.drop(idx)
                found = True
                break
        if not found:
            break

    # 按原DataFrame的顺序返回结果
    return df.loc[sorted(selected_indices)]

# 测试示例
df = pd.DataFrame({'column1': [1, 2, 3, 1, 3, 4],
                   'column2': [5, 6, 7, 8, 9, 7]})

print("Original DataFrame:")
print(df)

result = max_unique_subset(df, 'column1', 'column2')
print("\nResulting DataFrame:")
print(result)

运行结果

Original DataFrame:
   column1  column2
0        1        5
1        2        6
2        3        7
3        1        8
4        3        9
5        4        7

Resulting DataFrame:
   column1  column2
0        1        5
1        2        6
4        3        9
5        4        7

原理说明

  1. 优先保留单关联行:这类行的某一列值仅对应另一列的唯一值,如果删除会直接丢失该列的唯一值,必须优先保留。
  2. 贪心处理冲突行:对于剩余的多关联行,依次选择不与已选行冲突的条目,直到无法再选为止。

这种方法在大多数场景下能得到最优解,且无需依赖复杂的图算法库,实现简单高效。

内容的提问来源于stack exchange,提问作者Sartem Cacartem

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 07:05:55