Python中如何按user_id分组后按规则筛选行并返回单条结果?
问题:DataFrame分组后按规则提取tier值
需求说明
对DataFrame按user_id分组后,每组仅返回一条tier结果,规则如下:
- 若
rank=1且tier≠Unknown,返回该tier(如用户a001) - 否则返回
rank=2对应的tier(如用户b001) - 若
rank=1且tier=Unknown,返回'no_tier'(如用户c001)
注:每个user_id的tier中Unknown仅出现一次。
原始DataFrame
user_id tier rank a001 High 1 a001 Low 2 a001 Unknown 3 b001 Unknown 1 b001 Mid 2 c001 Unknown 1
预期结果
tier High Mid no_tier
你的错误代码
def get_tier(x): if x['rank'] ==1 and x['tier'] != 'Unknown': return x['tier'] elif x['rank'] == 2: return x['tier'] else: return 'no_tier' df.goupby('user_id').apply(lambda x : x.apply(get_tier), axis = 1).iloc[0]).reset_index()
错误点说明
goupby拼写错误,正确应为groupby- 分组后
apply的逻辑错误:x是每个用户的子DataFrame,不是单行数据,嵌套的x.apply(get_tier, axis=1)会对每行调用函数,但最后取iloc[0]的逻辑混乱,无法得到每组唯一的结果。
正确解法
方法一:修正分组apply逻辑
重写函数处理每个用户的子DataFrame,按规则判断返回结果:
import pandas as pd # 构造原始DataFrame df = pd.DataFrame({ 'user_id': ['a001', 'a001', 'a001', 'b001', 'b001', 'c001'], 'tier': ['High', 'Low', 'Unknown', 'Unknown', 'Mid', 'Unknown'], 'rank': [1, 2, 3, 1, 2, 1] }) def get_tier(group): # 获取当前用户rank=1的行 rank1_row = group[group['rank'] == 1].iloc[0] if rank1_row['tier'] != 'Unknown': return rank1_row['tier'] # 检查是否存在rank=2的行 rank2_rows = group[group['rank'] == 2] if not rank2_rows.empty: return rank2_rows.iloc[0]['tier'] # 对应rank=1且tier=Unknown的情况 return 'no_tier' # 分组应用函数,得到结果 result = df.groupby('user_id').apply(get_tier).reset_index(name='tier') # 若仅需要tier列,可执行以下操作 result = result['tier'] print(result)
输出结果:
0 High 1 Mid 2 no_tier Name: tier, dtype: object
方法二:高效筛选法(适合大数据量)
通过排序和优先级标记,避免循环式apply,提升效率:
import pandas as pd df = pd.DataFrame({ 'user_id': ['a001', 'a001', 'a001', 'b001', 'b001', 'c001'], 'tier': ['High', 'Low', 'Unknown', 'Unknown', 'Mid', 'Unknown'], 'rank': [1, 2, 3, 1, 2, 1] }) # 按用户和rank升序排序,确保rank小的行在前 df_sorted = df.sort_values(['user_id', 'rank']) # 给每行标记优先级:规则1优先级最高,规则2次之,规则3最低 df_sorted['priority'] = 0 df_sorted.loc[(df_sorted['rank'] == 1) & (df_sorted['tier'] != 'Unknown'), 'priority'] = 3 df_sorted.loc[df_sorted['rank'] == 2, 'priority'] = 2 df_sorted.loc[(df_sorted['rank'] == 1) & (df_sorted['tier'] == 'Unknown'), 'priority'] = 1 # 每组取优先级最高的行的tier值 result = df_sorted.groupby('user_id').apply(lambda x: x.loc[x['priority'].idxmax(), 'tier']).reset_index(name='tier') result = result['tier'] print(result)
输出结果和方法一一致。
内容的提问来源于stack exchange,提问作者Jammy Wang
相关产品推荐
相关产品推荐

