图解Pandas的排名rank机制
图解Pandas的排名rank机制
在我们的生活经常会遇到各种排名问题:学生成绩排名、销售员业绩排名、各种比赛排名等。在之前一篇关于SQL的文章-《面试必备:SQL排名和窗口函数》中有提到过如何使用SQL来实现3种主要的排名方式:顺序排名、跳跃排名和密集排名。
Pandas这个强大的数据分析库也可以快速实现多种排名方式,主要是通过rank函数来解决的,本文将通过多个例子来讲解。
imageRank参数
下面是rank函数的主要参数为:
DataFrame.rank(axis=0,
method='average',
numeric_only=None,
na_option='keep',
ascending=True,
pct=False)
参数的具体解释为:
- axis:表示排名是根据哪个轴,axis=0表示横轴,axis=1表示纵轴
- method:取值可以为'average','first','min', 'max','dense';后面重点介绍,默认是average
- numeric_only:是否仅仅计算数字型的columns
- na_optiaon:NaN值是否参与排名以及如何排名,取值为keep、top、bottom
- ascending:升序还是降序;默认是升序
- pct:是否以排名的百分比显示排名;所有排名和最大排名的百分比
本文将会讲解rank函数在Series和DataFrame两种数据类型的使用。
Series排名
import pandas as pd
import numpy as np
首先我们模拟一份简单的数据:
image参数method
1、默认情况的排名method="average":
image2、method="first"
根据值在原始数据中出现的顺序进行排名,相同数值的排名依次加1:
image解释上面两个结果:
- first:直接根据数值的大小顺序进行排名
- average:表示的是,如果两个数值相同,排名是它们的均值
我们看到first的使用就是数值的自然顺序出现的排名;在使用average的情况解释如下:
-5的排名是1.0,0的排名是2.0,3的排名是3.0,5(3号索引位置)的排名是4.0,5(6号索引位置)的排名是5.0,8(0号索引位置)的排名是6.0,8(2号索引)的排名是7.0
通过average的使用,相同数值的排名rank会取出均值,5的排名统一成4.5,8的排名统一成6.5
3、max和min的使用
[图片上传失败...(image-d9f522-1625217642139)]
image比如当:method= "max":如果数值相同,取该数值最大的那个排名。比如5最大的排名是5,所以原始数据中两个5的排名都是5;两个8的排名都是7(8的两个排名是6和7,取大值7)
4、method="dense"
相同的数值排名相同,下个数值的排名不出现跳跃
image这个时候排名的时候是不会出现跳跃的情况
参数ascending
默认情况下是升序的情况,可以使用降序:值越大,排名越靠前:
image image数值中8的排名,如果是method=“first”,排名是1和2,如是使用average,排名则会变成1.5;其他的数值排名类似。再看看max的情况:
image参数pct
是否以排名的百分比显示排名;所有排名和最大排名的百分比
image上面的排名是如何计算出来的呢?我们最大的排名是7:
image image再比如dense情况下的pct参数使用类似:
image参数na_option
这个参数表示的是空值是否参与排名,取值为keep、top、bottom。我们再模拟一份带有空值的数据:
image看看3种不同的情况:
image image imageDataFrame排名
模拟数据
还是先模拟一份数据:
df0 = pd.DataFrame({"科目":["语文","语文","语文","语文","语文","数学","数学","数学","数学","数学"],
"姓名":["小明","小苏","小周","小孙","小王","小明","小苏","小周","小孙","小王"],
"分数":[137,125,125,115,115,80,111,130,130,140]})
df = df0.copy() # 生成一个副本df
df
image
单个科目排名
比如我们想看语文这门科目的排名情况,取出同学们的语文成绩:
image分别使用顺序排名、跳跃排名和密集排名来展示排名情况:
# 默认排名方式
df1["均值排名_默认"] = df1["分数"].rank(ascending=False)
df1["跳跃排名_min"] = df1["分数"].rank(method="min",ascending=False)
df1["跳跃_max"] = df1["分数"].rank(method="max",ascending=False)
df1["密集排名_dense"] = df1["分数"].rank(method="dense",ascending=False)
df1
image
同学总分排名
先通过transform生成每个同学的总分:
df["总分"] = df.groupby("姓名")["分数"].transform("sum")
df
image
我们使用密集排名的方式对总分进行排名:
image分组取出指定排名
我们现在看到每个科目下的第二名的学生,如果成绩相同,排名相同(不跳跃),我们使用密集排名:
# 定义一个排名第二的函数
def rank_second(x):
return x[x["分数"].rank(method="dense",ascending=False) == 2]
image
我们看看真实数据中每个科目的第二名同学:
image上面自定义的排名第二的函数分为两步;
1、先实现密集排名
image2、指定排名等于2
image当我们使用这个自定义函数的时候,我们需要先根据科目进行分组,然后再每个组中单独使用这个自定义函数,就能获得每个科目下的第二名。
总结
讲解完rank函数的使用,可以和SQL中的窗口函数进行类比:
- row_number:顺序排名,rank函数的中的method=first
- rank:跳跃排名,rank函数的中的method=min
- dense_rank:密集排名,rank函数的中的method=dense
最后附上rank函数的官网学习地址,还得多看官网:
https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.rank.html