Pandas多列排序与多列排名

Pandas多列排序与多列排名

    • 1、需求背景
    • 2、数据准备
    • 3、实验过程
    • 4、实现方式
    • 5、实验结论

1、需求背景


工作中,我们可能会遇到这样的需求:按汇总指标A列排名,指标A列值相同,则按指标B列排名

本文将通过一个小实验介绍如何使用Pandas在多个列上进行排序排名操作

2、数据准备

import numpy as np
import pandas as pd
import glob
import os

files = glob.glob(os.path.join(r'C:\Users\cc\Desktop\Test', '*.xlsx'))

# 读取并合并Excel
df_res = pd.DataFrame()
for file in files:
    # 读取
    df = pd.read_excel(file)
    # 合并
    df_res = pd.concat([df_res, df], ignore_index=True)

print(df_res.to_string())
'''
    姓名  月度积分  月度评分
0   张三     5     9
1   李四     4     9
2   赵六     4     8
3   王五     5    10
4   张三     4     8
5   李四     5    10
6   王五     5    10
7   赵六     4     9
8   张三     4     8
9   李四     4     8
10  赵六     4     9
11  王五     4     9
12  张三     5     7
13  李四     5     9
14  王五     5     9
15  赵六     4     9
'''

3、实验过程


实验需求: 将每个人的积分、评分汇总,并按总积分排名,总积分一致时,按总评分排名,最终结果按排名升序

# 计算总积分总评分
df = df_res.\
    groupby('姓名', as_index=False).agg({'月度积分': 'sum', '月度评分': 'sum'}).\
    rename(columns={'月度积分': '总积分', '月度评分': '总评分'})

# 指定姓名、总积分列去重,保留第一个
df.drop_duplicates(subset=['姓名', '总积分'], keep='first', inplace=True)
print(df.to_string())
'''
   姓名  总积分  总评分
0  张三   18    32
1  李四   18    36
2  王五   19    38
3  赵六   16    35
'''

4、实现方式


1)方式1

# 按总积分进行排序,若总积分相同则按照总评分排序
df = df.sort_values(by=['总积分', '总评分'], ignore_index=True, ascending=[False, False])
print(df.to_string())
'''
   姓名  总积分  总评分
0  王五   19   38
1  李四   18   36
2  张三   18   32
3  赵六   16   35
'''
df['总排名'] = df[['总积分', '总评分']].rank(method='dense', ascending=[False, False])
print(df.to_string())
'''
ValueError: Cannot set a DataFrame with multiple columns to the single column 总排名
'''

上述方式多列排序没有问题,但多列排名报错

2)方式2

# 按总积分排名
df['总排名'] = df['总积分'].rank(method='dense', ascending=False)
print(df.to_string())
'''
   姓名  总积分  总评分  总排名
0  张三   18    32     2.0
1  李四   18    36     2.0
2  王五   19    38     1.0
3  赵六   16    35     3.0
'''
# 按总积分进行排序,若总积分相同则按照总评分排序
df.sort_values(by=['总积分', '总评分'], ascending=[False, False], inplace=True)
print(df.to_string())
'''
   姓名  总积分  总评分  总排名
2  王五   19    38     1.0
1  李四   18    36     2.0
0  张三   18    32     2.0
3  赵六   16    35     3.0
'''

上述方式不会报错,但最终结果按“1 2 2 3 ...”dense_rank())方式进行了排名,没有达到按总积分排名,总积分一致时,按总评分排名的要求

相当于实现了按总积分进行排序,若总积分相同则按照总评分排序的需求

3)方式3

# 使用辅助列
df['辅助列'] = df.eval('总积分*100 + 总评分')
# print(df.to_string())
df['总排名'] = df['辅助列'].rank(method='dense', ascending=False)
df.sort_values(by='总排名', ignore_index=True, ascending=True, inplace=True)
# 删除辅助列
df.drop(axis=1, columns='辅助列', inplace=True)
print(df.to_string())
'''
   姓名  总积分  总评分  总排名
0  王五   19    38     1.0
1  李四   18    36     2.0
2  张三   18    32     3.0
3  赵六   16    35     4.0
'''

上述方式可以实现按总积分进行排名,若总积分相同则按照总评分排名的需求(row_number()),需要借助辅助列进行操作

补充: rank()方法的pct参数使用

pct:返回相对排名(每个值在数据中的位置的百分比),百分比表示每个元素在数据集中的相对位置,默认False

# 按照总评分计算相对排名
# 例如一个相对排名为0.75的人,他的评分高于75%的人
df['相对排名'] = df['总评分'].rank(pct=True)
print(df.to_string())
'''
   姓名  总积分  总评分  总排名  相对排名
0  王五   19    38     1.0    1.00
1  李四   18    36     2.0    0.75
2  张三   18    32     3.0    0.25
3  赵六   16    35     4.0    0.50
'''
# 获取相对排名前50%的人
print(df.query('相对排名 > 0.50'))
'''
   姓名  总积分  总评分  总排名  相对排名
0  王五   19    38     1.0    1.00
1  李四   18    36     2.0    0.75
'''

5、实验结论


通过本次小实验,结合Hive的排序函数,我们发现:

rank():值相同时重复,总数不变,相当于Pandas的rank(method='min'),如1 2 2 4 ...

dense_rank():值相同时重复,总数减少,相当于Pandas的rank(method='dense'),如1 2 2 3 ...

row_number():始终按顺序排序,相当于Pandas的rank(method='first'),如1 2 3 4 ...

另外,Pandas的rank()函数不支持多列排名,需要通过辅助列实现;但支持sort_values()多列排序


你可能感兴趣的:(#,Python,#,数据分析,#,Hive,pandas,python)