如何在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
原理说明
- 优先保留单关联行:这类行的某一列值仅对应另一列的唯一值,如果删除会直接丢失该列的唯一值,必须优先保留。
- 贪心处理冲突行:对于剩余的多关联行,依次选择不与已选行冲突的条目,直到无法再选为止。
这种方法在大多数场景下能得到最优解,且无需依赖复杂的图算法库,实现简单高效。
内容的提问来源于stack exchange,提问作者Sartem Cacartem
相关产品推荐
相关产品推荐

