如何在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
相关产品推荐
相关产品推荐

