按行处理DataFrame指定列:仅当所有列值重复时保留首个副本
解决方案:按行处理指定列子集,仅当所有值相同时去重保留首个
这是此前两个技术问题的扩展:按行删除指定列子集的重复项仅保留首个副本、按行删除指定列子集的重复项仅当重复数≥3时保留首个副本。现有一个约700万行的DataFrame,示例代码如下:
import pandas as pd import numpy as np data = {'date': ['2023-02-22', '2023-02-21', '2023-02-23'], 'x1': ['descx1a', 'descx1b', 'descx1c'], 'x2': ['ALSFNHF950', 'KLUGUIF615', np.nan], 'x3': [np.nan, np.nan, 24319.4], 'x4': [np.nan, np.nan, 24334.15], 'x5': [np.nan, np.nan, 24040.11], 'x6': [404.29, 75.21, 24220.34], 'x7': [np.nan, np.nan, np.nan], 'v': [np.nan, np.nan, np.nan], 'y': [404.29, 75.33, np.nan], 'ay': [np.nan, np.nan, np.nan], 'by': [np.nan, np.nan, np.nan], 'cy': [np.nan, np.nan, np.nan], 'gy': [np.nan, np.nan, np.nan], 'uap': [404.29, 75.33, np.nan], 'ubp': [404.29, 75.33, np.nan], 'sf': [np.nan, 2.0, np.nan]} df = pd.DataFrame(data)
需求说明
仅当指定列子集中的所有列值完全相同时,删除重复项并仅保留首个副本;若子集内仅部分列值重复,则不做处理。
例如指定列子集为['x6', 'y', 'uap', 'ubp']时,输出结果如下:
# 输出的DataFrame对应数据 data = {'date': ['2023-02-22', '2023-02-21', '2023-02-23'], 'x1': ['descx1a', 'descx1b', 'descx1c'], 'x2': ['ALSFNHF950', 'KLUGUIF615', np.nan], 'x3': [np.nan, np.nan, 24319.4], 'x4': [np.nan, np.nan, 24334.15], 'x5': [np.nan, np.nan, 24040.11], 'x6': [404.29, 75.21, 24220.34], 'x7': [np.nan, np.nan, np.nan], 'v': [np.nan, np.nan, np.nan], 'y': [np.nan, 75.33, np.nan], 'ay': [np.nan, np.nan, np.nan], 'by': [np.nan, np.nan, np.nan], 'cy': [np.nan, np.nan, np.nan], 'gy': [np.nan, np.nan, np.nan], 'uap': [np.nan, 75.33, np.nan], 'ubp': [np.nan, 75.33, np.nan], 'sf': [np.nan, 2.0, np.nan]}
实现代码
针对700万行的大数据量,采用矢量化操作保证效率,避免逐行循环:
# 指定需要处理的列子集 subset = ['x6', 'y', 'uap', 'ubp'] # 提取子集数据 subset_df = df[subset] # 1. 筛选出需要处理的行:所有非NaN值完全相同,且不是全NaN的行 # 获取每行第一个非NaN值(处理开头有NaN的情况) first_non_nan = subset_df.bfill(axis=1).iloc[:, 0] # 检查每行所有值是否与第一个非NaN值一致 all_values_same = (subset_df == first_non_nan[:, None]).all(axis=1) # 排除全NaN的行 all_nan_rows = subset_df.isna().all(axis=1) # 最终需要处理的行掩码 process_mask = all_values_same & ~all_nan_rows # 2. 创建替换掩码:仅保留每行第一个列的值,其余列设为NaN(仅在需要处理的行生效) replace_mask = pd.DataFrame(False, index=subset_df.index, columns=subset_df.columns) replace_mask.iloc[:, 0] = True # 第一列保留原值 # 不需要处理的行,所有列都保留原值 replace_mask = replace_mask | ~process_mask[:, None] # 3. 应用掩码处理子集列 processed_subset = subset_df.where(replace_mask) # 4. 将处理后的子集列替换回原DataFrame df[subset] = processed_subset # 查看结果 print(df)
代码说明
- 矢量化判断:通过
bfill和广播操作快速判断每行所有值是否一致,避免逐行循环,适合大数据量 - 掩码控制:通过双层掩码精准控制需要替换的位置,确保只有符合条件的行才会被处理
- 无侵入修改:仅修改指定列子集,原DataFrame的其他列保持不变
内容的提问来源于stack exchange,提问作者anarchy
相关产品推荐
相关产品推荐

