如何在pandas DataFrame中按比例随机删除指定列重复行
解决方案
原有代码失效原因
你之前写的代码逻辑不符合需求:先全局随机采样50%行后调用drop_duplicates(subset=['A']),会直接把A列所有重复值的行全部删除,最终每个A的取值只会保留1行,完全达不到「按A列分组、每组删除指定比例行」的效果。
正确实现的核心逻辑是:按A列对数据分组,每个分组单独随机采样保留对应比例的行,最后把所有分组合并为新的DataFrame。
基础需求:所有分组统一删除50%行
直接按A列分组,每组采样50%的行保留即可,代码如下:
# 每组随机保留50%行,删除剩余50% df_basic = df.groupby('A', group_keys=False).apply( lambda x: x.sample(frac=0.5) ).reset_index(drop=True)
如果需要结果可复现,可以在sample()中传入random_state=固定整数参数固定随机种子。运行后pandas会自动对每组保留的行数做取整处理,输出结构和你给出的示例一致。
进阶需求:每个分组按自定义随机比例删除行
首先把A列的唯一值和生成的随机删除比例做键值对映射,分组采样时根据当前分组的取值读取对应的保留比例即可,全程不需要硬编码:
import random # 获取A列所有唯一值,顺序和生成随机比例列表的顺序对齐 a_unique = df['A'].unique() # 生成每个分组对应的删除比例,取值范围30%-50% del_percent_list = [random.randint(30, 50) for _ in range(len(a_unique))] # 构建A值到保留比例的映射:保留比例 = 1 - 删除比例/100 keep_ratio_map = {val: (100 - p)/100 for val, p in zip(a_unique, del_percent_list)} # 按分组采样对应比例的行 df_adv = df.groupby('A', group_keys=False).apply( lambda x: x.sample(frac=keep_ratio_map[x.name]) ).reset_index(drop=True)
如果需要精确控制每组保留行数的取整规则(比如固定向上取整、向下取整),可以改用n参数指定保留行数,示例如下:
import math # 每组保留行数向上取整 df_adv = df.groupby('A', group_keys=False).apply( lambda x: x.sample(n=math.ceil(len(x) * keep_ratio_map[x.name])) ).reset_index(drop=True)
注意事项
- 生成随机比例列表时,要保证
df['A'].unique()的取值顺序和生成列表的顺序一一对应,使用字典映射可以避免后续顺序错乱导致比例匹配错误 groupby时设置group_keys=False是为了避免把分组键加到结果的多层索引里,减少后续重置索引的额外处理- 如果需要更直观的删除逻辑,也可以对每组采样要删除的行索引,再调用
drop()方法删除对应行,和采样保留的逻辑完全等价
内容的提问来源于stack exchange,提问作者user14073111
相关产品推荐
相关产品推荐

