一文了解Pandas庫的分組的使用
分組模式及其對(duì)象
分組的一般模式
分組操作在日常生活中使用極其廣泛,比如
- 依據(jù)性別分組,統(tǒng)計(jì)全國(guó)人口的壽命平均值
- 依據(jù)季節(jié)分組,對(duì)每個(gè)季節(jié)的溫度進(jìn)行組內(nèi)的標(biāo)準(zhǔn)化
- 依據(jù)班級(jí)分子篩選組內(nèi)數(shù)學(xué)分?jǐn)?shù)的平均值超過80分的班級(jí)
因此,想要實(shí)現(xiàn)分組操作,必須明確三個(gè)要素:分組依據(jù)、數(shù)據(jù)來源、操作及其返回結(jié)果。
df.groupby(分組依據(jù))[數(shù)據(jù)來源].使用操作
例如:按照性別統(tǒng)計(jì)身高中位數(shù)
df = pd.read_csv('data/learn_pandas.csv')
print(df.groupby('Gender')['Height'].median())
#Gender
#Female 159.6
#Male 173.4
#Name: Height, dtype: float64
分組依據(jù)的本質(zhì)
如果現(xiàn)在需要根據(jù)多個(gè)維度進(jìn)行分組,只需在groupby中傳入相應(yīng)列名構(gòu)成的列表即可。例如,現(xiàn)希望根據(jù)學(xué)校和性別進(jìn)行分組,統(tǒng)計(jì)身高的均值
print(df.groupby(['School','Gender'])['Height'].mean()) #School Gender #Fudan University Female 158.776923 # Male 174.212500 #Peking University Female 158.666667 # Male 172.030000 #Shanghai Jiao Tong University Female 159.122500 # Male 176.760000 #Tsinghua University Female 159.753333 # Male 171.638889 #Name: Height, dtype: float64
目前為止,groupby的分組依據(jù)都是直接可以從列中按照名字獲取的,那如果通過一定的復(fù)雜邏輯來分組,例如根據(jù)學(xué)生體重是否超過總體均值來分組,同樣還是計(jì)算身高的均值
condition = df.Weight > df.Weight.mean() #體重大于平均體重 print(df.groupby(condition)['Height'].mean()) #Weight #False 159.034646 #True 172.705357 #Name: Height, dtype: float64
可以通過drop_duplicates知道具體的組類別
print(df[['School','Gender']].drop_duplicates()) # School Gender #0 Shanghai Jiao Tong University Female #1 Peking University Male #2 Shanghai Jiao Tong University Male #3 Fudan University Female #4 Fudan University Male #5 Tsinghua University Female #9 Peking University Female #16 Tsinghua University Male print(df.groupby([df['School'], df['Gender']])['Height'].mean()) #School Gender #Fudan University Female 158.776923 # Male 174.212500 #Peking University Female 158.666667 # Male 172.030000 #Shanghai Jiao Tong University Female 159.122500 # Male 176.760000 #Tsinghua University Female 159.753333 # Male 171.638889 #Name: Height, dtype: float64
Groupby對(duì)象
具體做分組操作時(shí),所調(diào)用的方法都來自于pandas中的groupby對(duì)象,這個(gè)對(duì)象上定義了許多方法。
通過ngroups屬性,可以得到分組個(gè)數(shù)
gb = df.groupby(['School', 'Grade']) print(gb.ngroups) #16
通過groups屬性,可以返回從組名映射到組索引列表的字典
gb = df.groupby(['School', 'Grade'])
res = gb.groups
print(res.keys())
#dict_keys([('Fudan University', 'Freshman'), ('Fudan University', 'Junior'), ('Fudan University', 'Senior'), ('Fudan University', 'Sophomore'), ('Peking University', 'Freshman'), ('Peking University', 'Junior'), ('Peking University', 'Senior'), ('Peking University', 'Sophomore'), ('Shanghai Jiao Tong University', 'Freshman'), ('Shanghai Jiao Tong University', 'Junior'), ('Shanghai Jiao Tong University', 'Senior'), ('Shanghai Jiao Tong University', 'Sophomore'), ('Tsinghua University', 'Freshman'), ('Tsinghua University', 'Junior'), ('Tsinghua University', 'Senior'), ('Tsinghua University', 'Sophomore')])
當(dāng)size作為DataFrame的屬性時(shí),返回的是表長(zhǎng)乘以表寬的大小,但在groupby對(duì)象上表示統(tǒng)計(jì)每個(gè)組的元素個(gè)數(shù)。
print(gb.size()) #School Grade #Fudan University Freshman 9 # Junior 12 # Senior 11 # Sophomore 8 #Peking University Freshman 13 # Junior 8 # Senior 8 # Sophomore 5 #Shanghai Jiao Tong University Freshman 13 # Junior 17 # Senior 22 # Sophomore 5 #Tsinghua University Freshman 17 # Junior 22 # Senior 14 # Sophomore 16 #dtype: int64
通過get_group方法可以直接獲取所在組對(duì)應(yīng)的行,此時(shí)必須知道組的具體名字
print(gb.get_group(('Fudan University', 'Freshman')))
# School Grade ... Test_Date Time_Record
#15 Fudan University Freshman ... 2020/1/1 0:05:25
#28 Fudan University Freshman ... 2020/1/7 0:05:24
#63 Fudan University Freshman ... 2019/10/31 0:04:00
#70 Fudan University Freshman ... 2019/11/19 0:04:07
#73 Fudan University Freshman ... 2019/9/26 0:03:31
#105 Fudan University Freshman ... 2019/12/11 0:04:23
#108 Fudan University Freshman ... 2019/12/8 0:05:03
#157 Fudan University Freshman ... 2019/9/11 0:04:17
#186 Fudan University Freshman ... 2019/10/9 0:04:21
#
#[9 rows x 10 columns]
聚合函數(shù)
內(nèi)置聚合函數(shù)
直接定義在groupby對(duì)象的聚合函數(shù),根據(jù)返回標(biāo)量值的原則,包括如下函數(shù):max/min/mean/median/count/all/any/idxmax/idxmin/mad/nunique/skew/quantile/sum/std/var/sem/size/prod
gb = df.groupby('Gender')['Height']
print(gb.idxmin())
#Gender
#Female 143
#Male 199
#Name: Height, dtype: int64
print(gb.quantile(0.95))
#Gender
#Female 166.8
#Male 185.9
#Name: Height, dtype: float64
這些聚合函數(shù)當(dāng)傳入的數(shù)據(jù)來源包含多個(gè)列時(shí),將按照列進(jìn)行迭代計(jì)算:
gb = df.groupby('Gender')[['Height', 'Weight']]
print(gb.max())
# Height Weight
#Gender
#Female 170.2 63.0
#Male 193.9 89.0
agg方法
雖然在groupby對(duì)象上定義了許多方便的函數(shù),但仍然有以下不便之處:
- 無法同時(shí)使用多個(gè)函數(shù)
- 無法對(duì)特定的列使用特定的聚合函數(shù)
- 無法使用自定義的聚合函數(shù)
- 無法直接對(duì)結(jié)果的列名在聚合前進(jìn)行自定義命名
使用多個(gè)函數(shù)
當(dāng)使用多個(gè)聚合函數(shù)時(shí),需要用列表的形式把內(nèi)置聚合函數(shù)對(duì)應(yīng)的字符串傳入,先前提到的所有字符串都是合法的。
gb = df.groupby('Gender')[['Height', 'Weight']]
print(gb.agg(['sum','idxmax','skew']))
# Height Weight
# sum idxmax skew sum idxmax skew
#Gender
#Female 21014.0 28 -0.219253 6469.0 28 -0.268482
#Male 8854.9 193 0.437535 3929.0 2 -0.332393
從結(jié)果看,此時(shí)的列索引為多級(jí)索引,第一層為數(shù)據(jù)源,第二層為使用的聚合方法,分別逐一對(duì)列使用聚合,因此結(jié)果為6列。
對(duì)特定的列使用特定的聚合函數(shù)
對(duì)于方法和列的特殊對(duì)應(yīng),可以通過構(gòu)造字典傳入agg中實(shí)現(xiàn),其中字典以列名為鍵,以聚合字符串或字符串列表為值。
print(gb.agg({'Height':['mean','max'], 'Weight':'count'}))
# Height Weight
# mean max count
#Gender
#Female 159.19697 170.2 135
#Male 173.62549 193.9 54
使用自定義函數(shù)
在agg中可以使用具體的自定義函數(shù),需要注意傳入函數(shù)的參數(shù)是之前數(shù)據(jù)源中的列,逐列進(jìn)行計(jì)算。
print(gb.agg(lambda x: x.mean()-x.min())) # Height Weight #Gender #Female 13.79697 13.918519 #Male 17.92549 21.759259
由于傳入的是序列,因此序列上的方法和屬性都是可以在函數(shù)中使用的,只需保證返回值是標(biāo)量即可。
def my_func(s):
res = 'High'
if s.mean() <= df[s.name].mean():
res = 'Low'
return res
print(gb.agg(my_func))
# Height Weight
#Gender
#Female Low Low
#Male High High
聚合結(jié)果重命名
如果想要對(duì)聚合結(jié)果的列名進(jìn)行重命名,只需要將上述函數(shù)的位置改寫成元組,元組的第一個(gè)元素為新的名字,第二個(gè)位置為原來的函數(shù),包括聚合字符串和自定義函數(shù)。
print(gb.agg([('range', lambda x: x.max()-x.min()), ('my_sum', 'sum')]))
# Height Weight
# range my_sum range my_sum
#Gender
#Female 24.8 21014.0 29.0 6469.0
#Male 38.2 8854.9 38.0 3929.0
注意,使用對(duì)一個(gè)或者多個(gè)列使用單個(gè)聚合的時(shí)候,重命名需要加方括號(hào),否則就不知道是新的名字還是手誤輸錯(cuò)的內(nèi)置函數(shù)字符串
print(gb.agg({'Height': [('my_func', my_func), 'sum'], 'Weight': [('range', lambda x:x.max())]}))
# Height Weight
# my_func sum range
#Gender
#Female Low 21014.0 63.0
#Male High 8854.9 89.0
變換和過濾
變換函數(shù)與transform方法
變換函數(shù)的返回值為同長(zhǎng)度的序列,最常用的內(nèi)置變換函數(shù)是累計(jì)函數(shù):cumcount/cumsum/cumprod/cummax/cummin,它們的使用方式和聚合函數(shù)類似,只不過完成的是組內(nèi)累計(jì)操作。
print(gb.cummax().head()) # Height Weight #0 158.9 46.0 #1 166.5 70.0 #2 188.9 89.0 #3 NaN 46.0 #4 188.9 89.0
當(dāng)用自定義變換時(shí)需要使用transform方法,被調(diào)用的自定義函數(shù),其傳入值為數(shù)據(jù)源的序列,與agg的傳入類型是一致的,其最后的返回結(jié)果是行列索引與數(shù)據(jù)源一致的DataFrame。
print(gb.transform(lambda x: (x-x.mean())/x.std()).head()) # Height Weight #0 -0.058760 -0.354888 #1 -1.010925 -0.355000 #2 2.167063 2.089498 #3 NaN -1.279789 #4 0.053133 0.159631
transform只能返回同長(zhǎng)度的序列,但事實(shí)上還可以返回一個(gè)標(biāo)量,這會(huì)使得結(jié)果被廣播到其所在的整個(gè)組,這種標(biāo)量廣播的技巧在特征工程中是非常常見的。
print(gb.transform('mean').head())
# Height Weight
#0 159.19697 47.918519
#1 173.62549 72.759259
#2 173.62549 72.759259
#3 159.19697 47.918519
#4 173.62549 72.759259
組索引和過濾
組過濾作為行過濾的推廣,指的是如果對(duì)一個(gè)組的全體所在行進(jìn)行統(tǒng)計(jì)的結(jié)果返回True則會(huì)被保留,False則該組會(huì)被過濾,最后把所有未被過濾的組其對(duì)應(yīng)的所在行拼接起來作為DataFrame返回。
在groupby對(duì)象中,定義了filter方法進(jìn)行組的篩選,其中自定義函數(shù)的輸入?yún)?shù)為數(shù)據(jù)源構(gòu)成的DataFrame本身,在之前例子中定義的groupby對(duì)象中,傳入的就是df[['Height', 'Weight']],因此所有表方法和屬性都可以在自定義函數(shù)中相應(yīng)地使用,同時(shí)只需保證自定義函數(shù)的返回為布爾值即可。
print(gb.filter(lambda x:x.shape[0]>100).head()) # Height Weight #0 158.9 46.0 #3 NaN 41.0 #5 158.0 51.0 #6 162.5 52.0 #7 161.9 50.0
跨列分組
apply的使用
在設(shè)計(jì)上,apply的自定義函數(shù)傳入?yún)?shù)與filter完全一致,只不過后者只允許返回布爾值。
def BMI(x):
Height = x['Height']/100
Weight = x['Weight']
BMI_value = Weight/Height * 2
return BMI_value.mean()
print(gb.apply(BMI))
#Gender
#Female 60.107477
#Male 84.438489
#dtype: float64
除了返回標(biāo)量之外,apply方法還可以返回一維Series和二維DataFrame,但它們產(chǎn)生的數(shù)據(jù)框維數(shù)和多級(jí)索引的層數(shù)應(yīng)當(dāng)如何變化?
標(biāo)量情況:結(jié)果得到的是 Series ,索引與 agg 的結(jié)果一致
gb = df.groupby(['Gender','Test_Number'])[['Height','Weight']] print(gb.apply(lambda x: 0)) #Gender Test_Number #Female 1 0 # 2 0 # 3 0 #Male 1 0 # 2 0 # 3 0 #dtype: int64 print(gb.apply(lambda x: [0, 0])) #Gender Test_Number #Female 1 [0, 0] # 2 [0, 0] # 3 [0, 0] #Male 1 [0, 0] # 2 [0, 0] # 3 [0, 0] #dtype: object
Series情況:得到的是DataFrame,行索引與標(biāo)量情況一致,列索引為Series的索引
print(gb.apply(lambda x: pd.Series([0,0],index=['a','b']))) # a b #Gender Test_Number #Female 1 0 0 # 2 0 0 # 3 0 0 #Male 1 0 0 # 2 0 0 # 3 0 0
DataFrame情況:得到的是DataFrame,行索引最內(nèi)層在每個(gè)組原先agg的結(jié)果索引上,再加一層返回的DataFrame行索引,同時(shí)分組結(jié)果DataFrame的列索引和返回的DataFrame列索引一致。
print(gb.apply(lambda x: pd.DataFrame(np.ones((2,2)), index = ['a','b'], columns=pd.Index([('w','x'),('y','z')]))))
# w y
# x z
#Gender Test_Number
#Female 1 a 1.0 1.0
# b 1.0 1.0
# 2 a 1.0 1.0
# b 1.0 1.0
# 3 a 1.0 1.0
# b 1.0 1.0
#Male 1 a 1.0 1.0
# b 1.0 1.0
# 2 a 1.0 1.0
# b 1.0 1.0
# 3 a 1.0 1.0
# b 1.0 1.0
到此這篇關(guān)于一文了解Pandas庫的分組的使用的文章就介紹到這了,更多相關(guān)Pandas 分組內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
基于opencv實(shí)現(xiàn)簡(jiǎn)單畫板功能
這篇文章主要為大家詳細(xì)介紹了基于opencv實(shí)現(xiàn)簡(jiǎn)單畫板功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-08-08
jupyter 實(shí)現(xiàn)notebook中顯示完整的行和列
這篇文章主要介紹了jupyter 實(shí)現(xiàn)notebook中顯示完整的行和列,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-04-04
tensorflow之獲取tensor的shape作為max_pool的ksize實(shí)例
今天小編就為大家分享一篇tensorflow之獲取tensor的shape作為max_pool的ksize實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-01-01
10 行Python 代碼實(shí)現(xiàn) AI 目標(biāo)檢測(cè)技術(shù)【推薦】
這篇文章主要介紹了10 行Python 代碼,實(shí)現(xiàn) AI 目標(biāo)檢測(cè)技術(shù),看完了代碼,我們?cè)谝黄鹆牧哪繕?biāo)檢測(cè)背后的技術(shù)背景,并解讀這10行Python代碼的由來和實(shí)現(xiàn)原理。感興趣的朋友跟隨小編一起看看吧2019-06-06
Django 對(duì)IP訪問頻率進(jìn)行限制的例子
今天小編就為大家分享一篇Django 對(duì)IP訪問頻率進(jìn)行限制的例子,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-08-08
Django框架教程之正則表達(dá)式URL誤區(qū)詳解
正則表達(dá)式對(duì)大家來說應(yīng)該都不陌生,下面這篇文章主要給大家介紹了關(guān)于Django框架教程之正則表達(dá)式URL誤區(qū)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2018-01-01
Python 正則表達(dá)式中的`^`和`[]`及常見含義
文章解析Python正則中^和[]的用途:^在字符集前取反,外表示開頭;[]定義字符集,支持范圍、取反及特殊字符處理,需注意與錨點(diǎn)及預(yù)定義類的區(qū)別,本文給大家介紹Python 正則表達(dá)式中的^和[]及含義,感興趣的朋友一起看看吧2025-06-06
使用Gitee自動(dòng)化部署python腳本的詳細(xì)過程
小編最近在自學(xué)python,在學(xué)習(xí)過程中有好多意向不到的收獲,真的很開心,今天重點(diǎn)給大家分享使用Gitee自動(dòng)化部署python腳本的詳細(xì)過程,包括安裝環(huán)境搭建及一些注意事項(xiàng),感興趣的朋友跟隨小編一起看看吧2021-05-05

