pandas groupby分組對象的組內排序解決方案
問題:
根據數據某列進行分組,選擇其中另一列大小top-K的的所在行數據
解析:
求解思路很清晰,即先用groupby對數據進行分組,然後再根據分組後的某一列進行排序,選擇排序結果後的top-K結果
案例:
取一下dataframe中B列各對象中C值最高所在的行
df = pd.DataFrame({"A": [2, 3, 5, 4], "B": ['a', 'b', 'b', 'a'], "C": [200801, 200902, 200704, 201003]})
Groupby的基本功能介紹
groupby以後返回DataFrameGroupBy對象,實際上還沒有進行任何計算,隻是一個暫時存儲的容器,
[In]df.groupby('B') [Out]<pandas.core.groupby.DataFrameGroupBy object at 0x11800f588>
對groupby結果進行簡單的列選取返回的也是DataFrameGroupBy/SeriesGroupBy對象,無法可視化
[In]df.groupby('B')['A'] # 返回SeriesGroupBy對象 [Out]<pandas.core.groupby.SeriesGroupBy object at 0x117f6b630> [In]df.groupby('B')['A','C'] # 返回DataFrameGroupBy對象 [Out]<pandas.core.groupby.DataFrameGroupBy object at 0x117fb84e0>
需要對DataFrameGroupBy進行計數、統計、agg聚合計算、apply映射計算和transform等操作,才能生成可視化的數據(下文僅以count和size函數為例展示,不涉及其它的操作)
[In] df.groupby('B', as_index=False)['A'].count() # 組內數據統計 [Out] B A 0 a 2 1 b 2 [In] df.groupby('B')['A'].size().reset_index(name='Size') # 組內數據統計,size和count的一個顯著區別在於count不考慮Nan,size考慮Nan [Out] B Size 0 a 2 1 b 2
解決方案一:
對DataFrameGroupBy對象,用apply函數進行某列的sort_values排序,再選出其中的最大值所在行
# 返回值是一個帶有multiindex的dataframe數據,其中level=0為groupby的by列,而level=1為原index [In] df.groupby('B').apply(lambda x: x.sort_values('C', ascending=False)) [Out] A B C B a 3 4 a 201003 0 2 a 200801 b 1 3 b 200902 2 5 b 200704 # 通過設置group_keys參數對multiindex進行優化 [In] df.groupby('B', group_keys=False).apply(lambda x: x.sort_values('C', ascending=False)) [Out] A B C 3 4 a 201003 0 2 a 200801 1 3 b 200902 2 5 b 200704 # 再次groupby,並調用內置的first()方法,取最大值 [In] df.groupby('B', group_keys=False).apply(lambda x: x.sort_values('C', ascending=False)).groupby('B').first().reset_index() [Out] B A C 0 a 4 201003 1 b 3 200902
解決方案二:
先對B進行整體的sort_values,在groupy取值
[In] df.sort_values('C', ascending=False).groupby('B').first().reset_index() [Out] B A C 0 a 4 201003 1 b 3 200902
問題拓展:
以上僅解決瞭Top-1的問題,如果是Top-k呢?
答案:將first()函數變為head()函數
[In] df.sort_values('C', ascending=False).groupby('B').head(2) [Out] A B C 3 4 a 201003 1 3 b 200902 0 2 a 200801 2 5 b 200704
總結:
1、方案二,即先排序再groupby取值更方便
2、pandas中API眾多,在實際使用時要捋清各步驟返回值的類型以方便記憶和聯想
補充:pandas分組groupby、agg,排序sort,連接concat、join
連接concat和join
橫向連接
pd.concat([df6,df7],axis=1) df6.join(df7) # df6的表格在前面,如需df7的表格在前需要交換位置
註意點:
1、concat這個方法,既可以實現橫向連接,也可以實現縱向連接,通過設置axis的值來控制,axis=1表示的是橫向連接,如果多個連接的對象,放在列表中
2、join也可以實現
縱向連接
pd.concat([df8,df9],ignore_index=True)
註意點:
1、進行縱向合並的數據,需要用[]集合起來
2、ignore_index忽略原有的行索引,重新排列
3、drop_duplicates()刪除重復數據
排序
#按照成績排序 df10.sort_values('score') #默認升序,從小到大 df10.sort_values(['score','group'],ascending=False,na_position='first') #sort各個屬性
參數 | 描述 |
---|---|
by | 字符串或者列表,如果是單個排序字段,使用的是字符串,如果指定多個,需要使用列表 |
ascending | True的時候,是按照升序,默認是升序 |
na_position | 表示的是空值的位置,’last’是默認的,’first’開始位置 |
分組
### groupby df11.groupby('class') df11.groupby(['class','grade']) for cls,data in df11.groupby(['class','grade']): print(cls) print(data)
註意點:
1、groupby 如果指定的是一個列,如果是多個列[]
2、groupby返回的是一個對象,所以不能直接訪問,可以使用for
篩選出分組之後的列
如果篩選出一列數據[[列名]],返回的是dataframe對象
如果篩選出多個列數據,直接使用[]和[[]]均可
總結[[列1,列2,。。。。]]
聚合函數 agg配合使用
dff.groupby('class')[['math']].agg(['mean','max','min','median','std'])
函數 | 描述 |
---|---|
mean | 均值 |
max | 最大值 |
min | 最小值 |
median | 中位數 |
std | 標準差 |
count | 計數 |
skew | 偏度 |
quantile | 指定分位數 |
以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。如有錯誤或未考慮完全的地方,望不吝賜教。
推薦閱讀:
- Python groupby函數圖文詳解
- pandas中groupby操作實現
- Pandas groupby apply agg 的區別 運行自定義函數說明
- python數據處理67個pandas函數總結看完就用
- pandas數據分組groupby()和統計函數agg()的使用