Pandas中的寶藏函數(shù)-rank()
所謂的排名,就是一組數(shù)據(jù),我們想要知道每一條數(shù)據(jù)在整體中的名次,需要的是輸出名次,并不改變原數(shù)據(jù)結(jié)構(gòu)。
排序會改變原來的數(shù)據(jù)結(jié)構(gòu),且不會返回名次,這一點區(qū)別需要弄明白。初學(xué)的時候容易弄混淆。
本文將通過一個實例,講清楚Pandas中rank()排名函數(shù)的應(yīng)用。下面是案例數(shù)據(jù),包括我、張三以及唐宋八大家的語文考試成績。
import pandas as pddata = pd.DataFrame({'班級':['1班','1班','1班','1班','1班','2班','2班','2班','2班','2班'],'姓名':['韓愈','柳宗元','歐陽修','蘇洵','蘇軾','蘇轍','曾鞏','王安石','張三','小伍哥'],'成績':[80,70,70,40,10,60,60,50,50,40]})#姓名長度不一樣的,加個符號調(diào)整下,這該死的強(qiáng)迫癥data['姓名'] = data['姓名'].str.rjust(3,'〇')

一、DataFrame的正常排名
Pandas中的排名,函數(shù)為rank(),使用也比較簡單,需要注意的是各種排名的差異,需要進(jìn)行充分理解,這樣在實際應(yīng)用中才不會出錯。
函數(shù)用法:
DataFrame.rank(axis=0,method='average',numeric_only=None,na_option='keep',ascending=True,pct=False)
參數(shù)說明:
axis:0或'index',1或'columns',默認(rèn)0,沿著行或列計算排名
method:'average','min','max','first','dense',默認(rèn)為'average',如何對具有相同值(即ties)的記錄組進(jìn)行排名:
average:組的平均等級
min:組中最低的排名
max:組中最高等級
first : 按排列順序排列,依次排列
dense:類似于 ‘min’,但組之間的排名始終提高1
numeric_only:bool,是否僅僅計算數(shù)字型的columns,布爾值
na_option:{'keep','top','bottom'},默認(rèn)為'keep',NaN值是否參與排名及如何排名
keep:將NaN等級分配給NaN值
top:如果升序,則將最小等級分配給NaN值
bottom:如果升序,則將最高等級分配給NaN值。
ascending:bool,默認(rèn)為True,元素是否應(yīng)該按升序排名。
pct:bool,默認(rèn)為False,是否以百分比形式顯示返回的排名。
所有的參數(shù)中,最核心的參數(shù)是method,一共5種排名方法,下面對這5種方法進(jìn)行對比,應(yīng)用的時候更好的去選擇。
1、method='first'
當(dāng)method='first'時,當(dāng)里兩個人的分?jǐn)?shù)相同時,分?jǐn)?shù)相同的情況下,誰先出現(xiàn)誰的排名靠前(當(dāng)method取值為min,max,average時,都是要參考“順序排名”的),表中的柳宗元和歐陽修分?jǐn)?shù)相同,但是柳宗元在表格的前面,所以排名第2,歐陽修排名第3。
班級 | 姓名 | 成績 | 成績(method='first') |
1班 | 〇韓愈 | 50 | 1 |
1班 | 柳宗元 | 30 | 2 |
1班 | 歐陽修 | 30 | 3 |
1班 | 〇蘇洵 | 20 | 4 |
1班 | 〇蘇軾 | 10 | 5 |
代碼如下:
data_1 = data[data['班級']=='1班']data_1['成績_first'] = data_1['成績'].rank(method='first',ascending=False)data_1班級 姓名 成績 成績_first0 1班 〇韓愈 50 1.01 1班 柳宗元 30 2.02 1班 歐陽修 30 3.03 1班 〇蘇洵 20 4.04 1班 〇蘇軾 10 5.0
2、method='min'
當(dāng)method='min'時,成績相同的同學(xué),取在順序排名中最小的那個排名作為該值的排名,會出現(xiàn)名次跳空,柳宗元和歐陽修分?jǐn)?shù)相同,在上面的排名中,分別排第2、第3,所以這里取兩個中最小的為排名名次2作為共同的名次。
班級 | 姓名 | 成績 | 成績(method='min') |
1班 | 〇韓愈 | 50 | 1 |
1班 | 柳宗元 | 30 | 2 |
1班 | 歐陽修 | 30 | 2 |
1班 | 〇蘇洵 | 20 | 4 |
1班 | 〇蘇軾 | 10 | 5 |
代碼如下:
data_1 = data[data['班級']=='1班']data_1['成績_min'] = data_1['成績'].rank(method='min',ascending=False)data_1班級 姓名 成績 成績_min0 1班 〇韓愈 50 1.01 1班 柳宗元 30 2.02 1班 歐陽修 30 2.03 1班 〇蘇洵 20 4.04 1班 〇蘇軾 10 5.0
3、method='max'
當(dāng)method='max'時,與上面的min相反,成績相同的同學(xué),取在順序排名中最大的那個排名作為該值的排名,,會出現(xiàn)名次跳空,柳宗元和歐陽修分?jǐn)?shù)相同,在順序排名中,分別排第2、第3,所以這里取兩個中最大的為排名名次3作為共同的名次。
班級 | 姓名 | 成績 | 成績_max |
1班 | 〇韓愈 | 50 | 1 |
1班 | 柳宗元 | 30 | 3 |
1班 | 歐陽修 | 30 | 3 |
1班 | 〇蘇洵 | 20 | 4 |
1班 | 〇蘇軾 | 10 | 5 |
代碼如下:
data_1 = data[data['班級']=='1班']data_1['成績_max'] = data_1['成績'].rank(method='max',ascending=False)data_1班級 姓名 成績 成績_max0 1班 〇韓愈 50 1.01 1班 柳宗元 30 3.02 1班 歐陽修 30 3.03 1班 〇蘇洵 20 4.04 1班 〇蘇軾 10 5.0
4、method='dense'
method='dense',dense是稠密的意思,即相同成績的同學(xué)排名相同,其他依次加1即可,不會出現(xiàn)名次跳空的情況。柳宗元和歐陽修分?jǐn)?shù)相同,在上面的排名中,分別排第2、第3,取相同排名2,這個看上去和min一樣的,但是下一名的排名發(fā)生了變化,〇蘇洵同學(xué)從第4名排到了第3名,排名數(shù)字連續(xù)的,沒有跳躍。
班級 | 姓名 | 成績 | 成績_dense |
1班 | 〇韓愈 | 50 | 1 |
1班 | 柳宗元 | 30 | 2 |
1班 | 歐陽修 | 30 | 2 |
1班 | 〇蘇洵 | 20 | 3 |
1班 | 〇蘇軾 | 10 | 4 |
代碼如下:
data_1 = data[data['班級']=='1班']data_1['成績_dense'] = data_1['成績'].rank(method='dense',ascending=False)data_1班級 姓名 成績 成績_dense0 1班 〇韓愈 50 1.01 1班 柳宗元 30 2.02 1班 歐陽修 30 2.03 1班 〇蘇洵 20 3.04 1班 〇蘇軾 10 4.0
5、method='average'
當(dāng)method='average'或者默認(rèn)值時,成績相同時,取順序排名中所有名次之和除以該成績的個數(shù),即為該成績的名次;比如上述排名中,30排名為2,3,那么 30的排名 = (2+3)/2=2.5,成績?yōu)?0的同學(xué)只有1個,且排名為1,那50的排名就位1/1=1。
班級 | 姓名 | 成績 | 成績_average |
1班 | 〇韓愈 | 50 | 1 |
1班 | 柳宗元 | 30 | 2.5 |
1班 | 歐陽修 | 30 | 2.5 |
1班 | 〇蘇洵 | 20 | 4 |
1班 | 〇蘇軾 | 10 | 5 |
代碼如下:
data_1 = data[data['班級']=='1班']data_1['成績_average'] = data_1['成績'].rank(method='average',ascending=False)data_1班級 姓名 成績 成績_average0 1班 〇韓愈 50 1.01 1班 柳宗元 30 2.52 1班 歐陽修 30 2.53 1班 〇蘇洵 20 4.04 1班 〇蘇軾 10 5.0
綜合上面的所有排名類型類型整體對比看看
班級 | 姓名 | 成績 | rank | rank_min | rank_max | rank_first | rank_dense |
1班 | 〇韓愈 | 50 | 1 | 1 | 1 | 1 | 1 |
1班 | 柳宗元 | 30 | 2.5 | 2 | 3 | 2 | 2 |
1班 | 歐陽修 | 30 | 2.5 | 2 | 3 | 3 | 2 |
1班 | 〇蘇洵 | 20 | 4 | 4 | 4 | 4 | 3 |
1班 | 〇蘇軾 | 10 | 5 | 5 | 5 | 5 | 4 |
data_1 = data[data['班級']=='1班']data_1['rank'] = data_1['成績'].rank(ascending=False)data_1['rank_min'] = data_1['成績'].rank(method='min',ascending=False)data_1['rank_max'] = data_1['成績'].rank(method='max',ascending=False)data_1['rank_first'] = data_1['成績'].rank(method='first',ascending=False)data_1['rank_dense'] = data_1['成績'].rank(method='dense',ascending=False)data_1班級 姓名 成績 rank rank_min rank_max rank_first rank_dense0 1班 〇韓愈 50 1.0 1.0 1.0 1.0 1.01 1班 柳宗元 30 2.5 2.0 3.0 2.0 2.02 1班 歐陽修 30 2.5 2.0 3.0 3.0 2.03 1班 〇蘇洵 20 4.0 4.0 4.0 4.0 3.04 1班 〇蘇軾 10 5.0 5.0 5.0 5.0 4.0
其他參數(shù)都比較簡單了,計算一行的排名,axis=0即可。
參數(shù)pct=True時,返回排名的分位數(shù),可以用于計算排名的百分比,非常方便。
= data[data['班級']=='1班']= data_1['成績'].rank(method='first',ascending=False,pct=True)data_1姓名 成績 成績_first0 1班 〇韓愈 80 0.21 1班 柳宗元 70 0.42 1班 歐陽修 70 0.63 1班 〇蘇洵 40 0.84 1班 〇蘇軾 10 1.0
二、DataFrame的分組排名
在上文中,我們看到了rank()函數(shù)對DataFrame直接排名,非常方便,也非常豐富,當(dāng)然,rank()也可以對經(jīng)過groupby分組后的數(shù)據(jù)進(jìn)行排名,分組排名的功能,讓數(shù)據(jù)分析更加的精細(xì)化,大大提高分析效率。直接使用開頭創(chuàng)建好的數(shù)據(jù)集,按班級排名,看看乜咯班級的第一名是誰。
= data.groupby('班級')['成績'].rank(method='dense')data姓名 成績 成績_dense0 1班 〇韓愈 50 4.01 1班 柳宗元 30 3.02 1班 歐陽修 30 3.03 1班 〇蘇洵 20 2.04 1班 〇蘇軾 10 1.05 2班 〇蘇轍 60 3.06 2班 〇曾鞏 60 3.07 2班 王安石 50 2.08 2班 〇張三 50 2.09 2班 小伍哥 40 1.0
同上面的直接排名,method一樣的可以使用各種方法,達(dá)到各種排名的目的。
= data.groupby('班級')['成績'].rank(method='average')data姓名 成績 成績_average0 1班 〇韓愈 80 5.01 1班 柳宗元 70 3.52 1班 歐陽修 70 3.53 1班 〇蘇洵 40 2.04 1班 〇蘇軾 10 1.05 2班 〇蘇轍 60 4.56 2班 〇曾鞏 60 4.57 2班 王安石 50 2.58 2班 〇張三 50 2.59 2班 小伍哥 40 1.0
三、Series的排名
對于Series。其實就是數(shù)據(jù)框的一列,沒啥多說的,一樣的方法就行,下面寫了兩個簡單的示例,大家參考下。
from pandas import Seriess = Series([1,3,2,1,6])s.rank()a 1.5c 4.0d 3.0b 1.5e 5.0
根據(jù)值在數(shù)組中出現(xiàn)的順序進(jìn)行排名,method='first'
='first')a 1.0c 4.0d 3.0b 2.0e 5.0
根據(jù)值在數(shù)組中出現(xiàn)的順序密集排名,method='dense'
='dense')a 1.0c 3.0d 2.0b 1.0e 4.0
碼字不易,大家多多分享傳播。求個點贊+在看。
一網(wǎng)打盡Pandas中的各種索引 iloc,loc,ix,iat,at,直接索引
