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

基于列值存在性聚合DataFrame的更优实现方案问询

问题描述

我有一个DataFrame,希望根据Result列中特定值的存在情况进行聚合:对于每个index1和index2分组,若分组内存在'A'或'As',则total_result列取值为'A';若不存在'A'但存在'B',则取值为'B',以此类推。目前已有可行代码,想询问是否有更简便的实现方式。

原始代码:

import pandas as pd
import numpy as np

df = pd.DataFrame({'index1':[1,2,2,2,3,3,4], 'index2':[1,2,2,2,3,3,4], 'Result':['A','','B','As','C','B','D']})

df_out = (df.groupby(['index1', 'index2'])
        .agg(A=('Result', lambda x: (x == 'A').any() | (x == 'As').any()),
            B=('Result', lambda x: (x == 'B').any()), 
            C=('Result', lambda x: (x == 'C').any()), 
            D=('Result', lambda x: (x == 'D').any()))
       .reset_index()
       .assign(tot_result = lambda x: np.where(x['A'], 'A',
                                                   np.where(x['B'], 'B',
                                                            np.where(x['C'], 'C', 'D'))))

       .drop(columns=['A', 'B', 'C', 'D'])
       )

给你几个更简洁的实现思路:

思路1:直接在分组apply里做优先级判断

把逻辑整合到一个lambda函数里,省去中间生成A/B/C/D列的步骤,可读性也更强:

import pandas as pd

df = pd.DataFrame({'index1':[1,2,2,2,3,3,4], 'index2':[1,2,2,2,3,3,4], 'Result':['A','','B','As','C','B','D']})

df_out = df.groupby(['index1', 'index2'])['Result'].apply(
    lambda grp: 'A' if ('A' in grp or 'As' in grp)
              else 'B' if 'B' in grp
              else 'C' if 'C' in grp
              else 'D'
).reset_index(name='total_result')

思路2:利用分类类型的排序特性

先把As映射成A,再将结果列转为指定优先级的分类类型,分组取最大值即可(因为分类的顺序由我们定义,最大值就是优先级最高的):

import pandas as pd
import numpy as np

df = pd.DataFrame({'index1':[1,2,2,2,3,3,4], 'index2':[1,2,2,2,3,3,4], 'Result':['A','','B','As','C','B','D']})

# 先处理映射:As转A,空值置为NaN
df['processed_result'] = df['Result'].replace({'As':'A', '':np.nan})
# 定义优先级分类,注意这里是逆序,因为max会取排序靠后的(优先级更高的)
df['processed_result'] = pd.Categorical(df['processed_result'], categories=['D','C','B','A'], ordered=True)

# 分组取max就是优先级最高的结果
df_out = df.groupby(['index1', 'index2'])['processed_result'].max().reset_index(name='total_result')

思路3:过滤空值后按优先级匹配

先过滤掉空字符串,把As转成A,然后分组后按优先级顺序检查哪个值存在,取第一个匹配的:

import pandas as pd
import numpy as np

df = pd.DataFrame({'index1':[1,2,2,2,3,3,4], 'index2':[1,2,2,2,3,3,4], 'Result':['A','','B','As','C','B','D']})

priority = ['A','B','C','D']
# 预处理:替换As为A,过滤空值
processed = df[df['Result'] != ''].replace({'Result':'As'}, 'A')

def get_top(grp):
    present = set(grp['Result'])
    for p in priority:
        if p in present:
            return p
    return 'D'  # 兜底

df_out = processed.groupby(['index1', 'index2']).apply(get_top).reset_index(name='total_result')

这几种方法都比原代码更简洁,避免了多层np.where嵌套和中间列的生成,逻辑也更直观。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 18:45:21