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

如何在Pandas中按排名分组计算均值并处理非唯一排名?

问题:Pandas按排名重组DataFrame并处理非唯一排名

我需要在Pandas DataFrame中按排名分组计算均值,同时想要创建一个以dates为索引、ranks为列,值取自scores的DataFrame。当前我通过melt/dropna/pivot的方式实现了后者,但该方法不够稳健,且不确定如何处理非唯一排名的情况。

环境设置

import numpy as np
import pandas as pd

rng = np.random.default_rng(42)
dates = pd.date_range('2024-08-01', '2024-08-07')
contestants = ['Alligator', 'Beryl', 'Chupacabra', 'Dandelion', 'Eggplant', 'Feldspar']

random_scores = rng.random(len(dates) * len(contestants))
random_scores = random_scores.reshape((len(dates), len(contestants)))
scores = pd.DataFrame(random_scores, dates, contestants)
scores.index.name = 'DATE'
scores.columns.name = 'CONTESTANT'
ranks = scores.rank(axis=1, method='first', ascending=False)
top3_ranks = ranks.where(ranks <= 3)

运行输出

scores DataFrame

CONTESTANT  Alligator     Beryl  Chupacabra  Dandelion  Eggplant  Feldspar
DATE
2024-08-01   0.773956  0.438878    0.858598   0.697368  0.094177  0.975622
2024-08-02   0.761140  0.786064    0.128114   0.450386  0.370798  0.926765
2024-08-03   0.643865  0.822762    0.443414   0.227239  0.554585  0.063817
2024-08-04   0.827631  0.631664    0.758088   0.354526  0.970698  0.893121
2024-08-05   0.778383  0.194639    0.466721   0.043804  0.154289  0.683049
2024-08-06   0.744762  0.967510    0.325825   0.370460  0.469556  0.189471
2024-08-07   0.129922  0.475705    0.226909   0.669814  0.437152  0.832678

top3_ranks DataFrame

CONTESTANT  Alligator  Beryl  Chupacabra  Dandelion  Eggplant  Feldspar
DATE
2024-08-01        3.0    NaN         2.0        NaN       NaN       1.0
2024-08-02        3.0    2.0         NaN        NaN       NaN       1.0
2024-08-03        2.0    1.0         NaN        NaN       3.0       NaN
2024-08-04        3.0    NaN         NaN        NaN       1.0       2.0
2024-08-05        1.0    NaN         3.0        NaN       NaN       2.0
2024-08-06        2.0    1.0         NaN        NaN       3.0       NaN
2024-08-07        NaN    3.0         NaN        2.0       NaN       1.0

我的尝试

melted_scores = scores.T.melt(value_name='SCORE')
melted_ranks = top3_ranks.T.melt(value_name='RANK')
melted_scores['RANK'] = melted_ranks['RANK']
desired_output = melted_scores.dropna().pivot(columns='RANK', index='DATE', values='SCORE')

得到的目标输出

RANK             1.0       2.0       3.0
DATE
2024-08-01  0.975622  0.858598  0.773956
2024-08-02  0.926765  0.786064  0.761140
2024-08-03  0.822762  0.643865  0.554585
2024-08-04  0.970698  0.893121  0.827631
2024-08-05  0.778383  0.683049  0.466721
2024-08-06  0.967510  0.744762  0.469556
2024-08-07  0.832678  0.669814  0.475705

解决方案

1. 更简洁的稳健实现(针对唯一排名)

直接利用stack和unstack操作,避免手动合并melt后的DataFrame,代码更简洁且不易出错:

desired_output = (
    scores.stack()
          .to_frame('SCORE')
          .join(top3_ranks.stack().rename('RANK'))
          .dropna()
          .reset_index()
          .pivot(index='DATE', columns='RANK', values='SCORE')
)

2. 处理非唯一排名(计算均值)

当排名存在重复(比如使用method='min'或method='max'导致同分数同排名),需要按DATE和RANK分组计算均值:

首先修改排名计算方式,制造非唯一排名场景:

# 使用min方法,相同分数会得到相同排名
ranks_non_unique = scores.rank(axis=1, method='min', ascending=False)
top3_ranks_non_unique = ranks_non_unique.where(ranks_non_unique <= 3)

然后执行分组聚合:

result_with_mean = (
    scores.stack()
          .to_frame('SCORE')
          .join(top3_ranks_non_unique.stack().rename('RANK'))
          .dropna()
          .groupby(['DATE', 'RANK'])['SCORE']
          .mean()
          .unstack('RANK')
)

这样即使同一日期同一排名下有多个分数,也会自动计算均值,输出格式保持一致。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 17:29:56