Pandas中基于列条件去除重复行的实现及进阶需求
问题描述
现有一个包含Action(取值为"start"、"end")、points(整数)、cards(整数)列的Pandas DataFrame,数据如下:
Action points cards start 1 1 start 2 2 start 2 3 end 1 1 end 2 2 end 2 3
需求:仅当Action等于"start"时,去除points值重复的行,期望输出如下:
Action points cards start 1 1 start 2 2 end 1 1 end 2 2 end 2 3
尝试以下命令均无效:
df[df["action"] == "start"].drop_duplicates(["points"]) # 无效果,未将结果赋值回原DataFrame df[df["action"] == "start"].drop_duplicates(["points"], inplace=True) # 报错,切片返回视图而非副本,无法原地修改 df[df["action"] == "start"] = df[df["action"] == "start"].drop_duplicates(["points"]) # 新增NaN行,左右两边索引不匹配
核心问题
- 在不能使用
dropna()的情况下,该如何实现需求? - 附加问题:若希望去除
(start, 2, 2)行而非(start, 2, 3)行,该如何操作?
解决方案
一、主问题实现(保留start组内points首次出现的行)
方法1:拆分数据后拼接(直观易懂)
将start和end数据分开处理,对start组去重后再与end组合并:
import pandas as pd # 构造原始数据 data = { "Action": ["start", "start", "start", "end", "end", "end"], "points": [1, 2, 2, 1, 2, 2], "cards": [1, 2, 3, 1, 2, 3] } df = pd.DataFrame(data) # 处理start数据:按points去重,保留第一个出现的行 start_df = df[df["Action"] == "start"].drop_duplicates(subset=["points"], keep="first") # 保留所有end数据 end_df = df[df["Action"] == "end"] # 合并并恢复原始索引顺序 result_df = pd.concat([start_df, end_df]).sort_index() print(result_df)
方法2:布尔索引筛选(高效简洁)
通过分组标记需要保留的行,无需拆分数据:
# 标记start组内points首次出现的行,end组全部保留 keep_mask = df.groupby(["Action", "points"]).cumcount() == 0 result_df = df[(df["Action"] == "end") | keep_mask] print(result_df)
二、附加问题实现(保留start组内points最后出现的行)
只需修改去重时的keep参数为"last",或调整布尔索引的标记逻辑:
方法1:拆分拼接+keep="last"
start_df = df[df["Action"] == "start"].drop_duplicates(subset=["points"], keep="last") end_df = df[df["Action"] == "end"] result_df = pd.concat([start_df, end_df]).sort_index() print(result_df)
方法2:布尔索引标记最后一行
# 计算每个(Action, points)组的行数 group_size = df.groupby(["Action", "points"]).transform("size") # 标记end组全部行,或start组内的最后一行 keep_mask = (df["Action"] == "end") | (df.groupby(["Action", "points"]).cumcount() == group_size - 1) result_df = df[keep_mask] print(result_df)
内容的提问来源于stack exchange,提问作者awy
相关产品推荐
相关产品推荐

