You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Python DataFrame的groupby与transform中用多条件生成NewRank

需求:基于GroupBy的条件判断生成NewRank列

我们需要结合groupby操作,通过条件判断在DataFrame中生成NewRank新列。

原始数据

创建目标DataFrame的代码如下:

import numpy as np
import pandas as pd
data = {'User': ['User1', 'User2', 'User3', 'User4', 'User5', 'User6', 'User7','User8', 'User9', 'User10','User11', 'User12', 'User13','User14', 'User15', 'User16'],
        'Type': ['A', 'B', 'B', 'A', 'A', 'B', float('nan'),'C','C','C','D','D','D','E','E','E'],
        'Usage': [100, 200, 150, 50, 75, 175, float('nan'),0,0,0,-3,-1,0,4,0,0],
        'OldRank': [3, 3, 1, 1, 2, 2, float('nan'),1,1,1,1,2,3,3,1,1]}
df = pd.DataFrame(data)

期望输出

最终需要得到的结果如下:

User Type  Usage  OldRank  NewRank
0    User1    A  100.0      3.0      3.0
4    User5    A   75.0      2.0      2.0
3    User4    A   50.0      1.0      1.0
1    User2    B  200.0      3.0      3.0
5    User6    B  175.0      2.0      2.0
2    User3    B  150.0      1.0      1.0
7    User8    C    0.0      1.0      0.0
8    User9    C    0.0      1.0      0.0
9   User10    C    0.0      1.0      0.0
12  User13    D    0.0      3.0      3.0
11  User12    D   -1.0      2.0      2.0
10  User11    D   -3.0      1.0      1.0
13  User14    E    4.0      3.0      3.0
14  User15    E    0.0      1.0      0.0
15  User16    E    0.0      1.0      0.0
6    User7  NaN    NaN      NaN      NaN

遇到的问题

尝试以下代码时触发ValueError,提示Series的真值判断不明确:

df['NewRank'] = df.groupby('Type')['Usage'].transform(lambda x: 0 if ( ((x==0).all()) | ( (x.min()>=0) & (df['OldRank']==0) ) ) else df['OldRank'] )

错误信息:

ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().

现有可行方案需要新增多个中间列,代码冗长且影响性能:

# 冗长的实现代码
df['R1'] = df.groupby('Type')['Usage'].transform(lambda x: (x==0).all() )
df['R2'] = df.groupby('Type')['Usage'].transform(lambda x: (x.min()>=0))
df['R3'] = df.groupby('Type')['Usage'].transform(lambda x: (x==0))

df['NewRank'] = np.where((df['R2']==True) & (df['R3']==True) | df['R1']==True ,0, df['OldRank'])

df = df.sort_values(by=['Type', 'Usage'], ascending=[True, False])

简洁高效的解决方案

可以通过一次分组计算生成所需标记,避免创建额外列,同时确保逻辑清晰:

# 生成分组级别的两个判断条件
grouped = df.groupby('Type')['Usage']
# 条件1:分组内所有Usage都是0
all_zero = grouped.transform(lambda x: (x == 0).all())
# 条件2:分组内Usage最小值≥0,且当前行Usage为0
min_non_neg_and_zero = grouped.transform(lambda x: x.min() >= 0) & (df['Usage'] == 0)

# 生成NewRank:满足任一条件则为0,否则保留OldRank
df['NewRank'] = np.where(all_zero | min_non_neg_and_zero, 0, df['OldRank'])

# 按Type和Usage降序排序,得到目标结果
df = df.sort_values(by=['Type', 'Usage'], ascending=[True, False])

逻辑说明

  1. all_zero:通过transform为每个分组标记是否所有Usage值都是0,结果是与原DataFrame长度一致的Series。
  2. min_non_neg_and_zero:先判断分组内Usage的最小值是否≥0(通过transform广播到每一行),再结合当前行Usage是否为0,得到第二个条件的标记。
  3. 生成NewRank:用np.where判断,只要满足all_zero或min_non_neg_and_zero任一条件,就赋值0,否则保留原OldRank。
  4. 排序:按照Type升序、Usage降序排序,匹配期望输出的顺序。

这种方式无需创建多余的中间列,直接通过分组计算和条件组合完成需求,性能更优。

内容的提问来源于stack exchange,提问作者Josue Medrano

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 19:24:55