如何获取Pandas DataFrame每行前3个最大值对应的列名?
Pandas按行提取Top N对应列名实现方案
核心需求为逐行计算流派列的数值排名,提取排名前3的列名作为新列,以下是可直接运行的实现代码:
步骤1:构造测试数据集
先对齐给出的样例数据结构:
import pandas as pd import numpy as np # 构建示例DataFrame df = pd.DataFrame({ 'Cluster': [1, 2, 3], 'Genre 1': [10, 53, 44], 'Genre 2': [31, 12, 73], 'Genre 3': [5, 6, 1], 'Genre 4': [3, 9, 9], 'Genre 5': [23, 7, 13] })
步骤2:按行提取Top3流派列名
方法1:向量化实现(推荐,大数据量性能更好)
利用numpy的argsort做行维度的向量化排序,避免逐行遍历的性能损耗:
# 筛选所有流派类列 genre_cols = [col for col in df.columns if col.startswith('Genre')] genre_values = df[genre_cols].values # 按行做降序排序,取前3位对应的列索引 # argsort默认返回升序排序的索引,对值取反即可实现降序 top3_index = np.argsort(-genre_values, axis=1)[:, :3] # 将索引映射为实际列名,写入新列 df['1st'] = [genre_cols[i] for i in top3_index[:, 0]] df['2nd'] = [genre_cols[i] for i in top3_index[:, 1]] df['3rd'] = [genre_cols[i] for i in top3_index[:, 2]]
运行后输出结果完全匹配预期:
| Cluster | Genre 1 | Genre 2 | Genre 3 | Genre 4 | Genre 5 | 1st | 2nd | 3rd |
|---|---|---|---|---|---|---|---|---|
| 1 | 10 | 31 | 5 | 3 | 23 | Genre 2 | Genre 5 | Genre 1 |
| 2 | 53 | 12 | 6 | 9 | 7 | Genre 1 | Genre 2 | Genre 4 |
| 3 | 44 | 73 | 1 | 9 | 13 | Genre 2 | Genre 1 | Genre 5 |
方法2:apply逐行实现(小数据集可读性更高)
如果数据量在万行以内,也可以用apply按行处理,代码逻辑更直观易读:
def fetch_top3(row): # 对当前行的流派值降序排序,取前3位的列名 top3_genres = row[genre_cols].sort_values(ascending=False).index[:3] return pd.Series([top3_genres[0], top3_genres[1], top3_genres[2]], index=['1st', '2nd', '3rd']) df[['1st', '2nd', '3rd']] = df.apply(fetch_top3, axis=1)
后续可视化预处理
做Top3流派可视化前,可以把宽表转成长表格式,直接对接matplotlib、seaborn等绘图库的输入要求:
plot_data = df.melt( id_vars=['Cluster'], value_vars=['1st', '2nd', '3rd'], var_name='rank', value_name='top_genre' )
注意事项
- 若某行存在数值相同的并列情况,上述两种方法默认将列顺序更靠前的流派判定为更高排名,如需自定义并列规则,可在排序时传入
key参数调整逻辑。 - 如果需要提取更多位次的结果,只需要修改取索引的切片范围、对应增加新列即可,逻辑完全通用。
内容的提问来源于stack exchange,提问作者Mettepen
相关产品推荐
相关产品推荐

