pandas 分組排序並保留原始列

場景

需要按照各個省份及全網進行分組,對各個指標的率值進行排序。
其實這一步一般是在sql中完成的,但由於

  1. 要分組排序的列較多,達30列以上,代碼十分不簡潔,python一兩行即可搞定
  2. 連接的數據庫爲mysql,本身沒有row_number() over( paritition by··· ···)的語句,實現起來較爲麻煩。
  3. 本次的原始數據每日只有5000行左右並不大

故直接用python將數據down下來進行處理。

實現

按照常理,直接groupby()分組再rank()排序即可

In[12]: result1.groupby(by='省份')[['投訴完結率', '二次投訴率']].rank(ascending=False, method = 'min')
Out[12]: 
     投訴完結率  二次投訴率
0      1.0    4.0
1      1.0    5.0
2      1.0    1.0
3      1.0    2.0
4      1.0    3.0
..     ...    ...
162    1.0    1.0
163    1.0    1.0
164    1.0    1.0
165    1.0    1.0
166    1.0    1.0

[167 rows x 2 columns]

但實際上得到的結果與sum() mean() max()等聚合運算得到的結果並不相同,這些聚合運算返回的Series或DataFrame的index爲“by=”的列。每一組僅返回一行數據。

In[20]: result1.groupby(by='省份').max()[['投訴完結率', '二次投訴率']].head()
Out[20]: 
       投訴完結率   二次投訴率
省份               
上海       1.0  0.0121
雲南       1.0  0.0244
全網       1.0  0.0120
內蒙古      1.0  0.0323
北京       1.0  0.0084

但rank()方法在原本數據的基礎上每一行都返回一個排名,最後得到的數據index仍爲原本的index,其他列是不顯示的。

爲了在結果中顯示其他列,有兩種方法:

  1. 如果需要將上述結果join回原result1,直接按index進行join/merge/concat即可, 但不可使用result1[['rank1','rank2']]=result1.groupby(by='省份')[['投訴完結率', '二次投訴率']].rank(ascending=False, method = 'min')這種方式直接增加一列,行的順序並不能自動對齊 ;
  2. 如僅需一列或幾列+計算得到的排名,而不需要原數據中其他列,則對result1在分組之前,將需要的列set_index更爲簡便
In [14]: result1.set_index(['省份','公司名稱']).groupby(by='002省份')[['投訴完結率', '二次投訴率']]\
.rank(ascending=False, method = 'min')
Out[14]: 
                 投訴完結率  二次投訴率
省份   公司名稱              
全網      s       1.0    4.0
        b       1.0    5.0
        yd       1.0    1.0
        y       1.0    2.0
        z       1.0    3.0
...                ...    ...
香港特別行政區 b       1.0    1.0
        s       1.0    1.0
        z       1.0    1.0
臺灣      z       1.0    1.0
        yd       1.0    1.0

[167 rows x 2 columns]
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章