微信公衆號:「Python讀財」
若有問題或建議,請公衆號留言
在平常的數據分析中,常常須要將數據根據某個(多個)字段劃分爲不一樣的羣體(group)進行分析,如電商領域將全國的總銷售額根據省份進行劃分,分析各省銷售額的變化狀況,社交領域將用戶根據畫像(性別、年齡)進行細分,研究用戶的使用狀況和偏好等。在Pandas中,上述的數據處理操做主要運用groupby
完成,這篇文章就介紹一下groupby
的基本原理及對應的agg
、transform
和apply
操做。python
爲了後續圖解的方便,採用模擬生成的10個樣本數據,代碼和數據以下:微信
company=["A","B","C"] data=pd.DataFrame({ "company":[company[x] for x in np.random.randint(0,len(company),10)], "salary":np.random.randint(5,50,10), "age":np.random.randint(15,50,10) } )
company | salary | age | |
---|---|---|---|
0 | C | 43 | 35 |
1 | C | 17 | 25 |
2 | C | 8 | 30 |
3 | A | 20 | 22 |
4 | B | 10 | 17 |
5 | B | 21 | 40 |
6 | A | 23 | 33 |
7 | C | 49 | 19 |
8 | B | 8 | 30 |
在pandas中,實現分組操做的代碼很簡單,僅需一行代碼,在這裏,將上面的數據集按照company
字段進行劃分:app
In [5]: group = data.groupby("company")
將上述代碼輸入ipython
後,會獲得一個DataFrameGroupBy
對象dom
In [6]: group Out[6]: <pandas.core.groupby.generic.DataFrameGroupBy object at 0x000002B7E2650240>
那這個生成的DataFrameGroupBy
是啥呢?對data
進行了groupby
後發生了什麼?ipython
所返回的結果是其內存地址,並不利於直觀地理解,爲了看看group
內部到底是什麼,這裏把group
轉換成list
的形式來看一看:函數
In [8]: list(group) Out[8]: [('A', company salary age 3 A 20 22 6 A 23 33), ('B', company salary age 4 B 10 17 5 B 21 40 8 B 8 30), ('C', company salary age 0 C 43 35 1 C 17 25 2 C 8 30 7 C 49 19)]
轉換成列表的形式後,能夠看到,列表由三個元組組成,每一個元組中,第一個元素是組別(這裏是按照company
進行分組,因此最後分爲了A
,B
,C
),第二個元素的是對應組別下的DataFrame
,整個過程能夠圖解以下:工具
總結來講,groupby
的過程就是將原有的DataFrame
按照groupby
的字段(這裏是company
),劃分爲若干個分組DataFrame
,被分爲多少個組就有多少個分組DataFrame
。因此說,在groupby
以後的一系列操做(如agg
、apply
等),均是基於子DataFrame
的操做。理解了這點,也就基本摸清了Pandas中groupby
操做的主要原理。下面來說講groupby
以後的常見操做。學習
聚合操做是groupby
後很是常見的操做,會寫SQL
的朋友對此應該是很是熟悉了。聚合操做能夠用來求和、均值、最大值、最小值等,下面的表格列出了Pandas中常見的聚合操做。spa
函數 | 用途 |
---|---|
min | 最小值 |
max | 最大值 |
sum | 求和 |
mean | 均值 |
median | 中位數 |
std | 標準差 |
var | 方差 |
count | 計數 |
針對樣例數據集,若是我想求不一樣公司員工的平均年齡和平均薪水,能夠按照下方的代碼進行:code
In [12]: data.groupby("company").agg('mean') Out[12]: salary age company A 21.50 27.50 B 13.00 29.00 C 29.25 27.25
若是想對針對不一樣的列求不一樣的值,好比要計算不一樣公司員工的平均年齡以及薪水的中位數,能夠利用字典進行聚合操做的指定:orm
In [17]: data.groupby('company').agg({'salary':'median','age':'mean'}) Out[17]: salary age company A 21.5 27.50 B 10.0 29.00 C 30.0 27.25
agg
聚合過程能夠圖解以下(第二個例子爲例):
transform
是一種什麼數據操做?和agg
有什麼區別呢?爲了更好地理解transform
和agg
的不一樣,下面從實際的應用場景出發進行對比。
在上面的agg
中,咱們學會了如何求不一樣公司員工的平均薪水,若是如今須要在原數據集中新增一列avg_salary
,表明員工所在的公司的平均薪水(相同公司的員工具備同樣的平均薪水),該怎麼實現呢?若是按照正常的步驟來計算,須要先求得不一樣公司的平均薪水,而後按照員工和公司的對應關係填充到對應的位置,不用transform
的話,實現代碼以下:
In [21]: avg_salary_dict = data.groupby('company')['salary'].mean().to_dict() In [22]: data['avg_salary'] = data['company'].map(avg_salary_dict) In [23]: data Out[23]: company salary age avg_salary 0 C 43 35 29.25 1 C 17 25 29.25 2 C 8 30 29.25 3 A 20 22 21.50 4 B 10 17 13.00 5 B 21 40 13.00 6 A 23 33 21.50 7 C 49 19 29.25 8 B 8 30 13.00
若是使用transform
的話,僅須要一行代碼:
In [24]: data['avg_salary'] = data.groupby('company')['salary'].transform('mean') In [25]: data Out[25]: company salary age avg_salary 0 C 43 35 29.25 1 C 17 25 29.25 2 C 8 30 29.25 3 A 20 22 21.50 4 B 10 17 13.00 5 B 21 40 13.00 6 A 23 33 21.50 7 C 49 19 29.25 8 B 8 30 13.00
仍是以圖解的方式來看看進行groupby
後transform
的實現過程(爲了更直觀展現,圖中加入了company
列,實際按照上面的代碼只有salary
列):
圖中的大方框是transform
和agg
所不同的地方,對agg
而言,會計算獲得A
,B
,C
公司對應的均值並直接返回,但對transform
而言,則會對每一條數據求得相應的結果,同一組內的樣本會有相同的值,組內求完均值後會按照原索引的順序返回結果,若是有不理解的能夠拿這張圖和agg
那張對比一下。
apply
應該是你們的老朋友了,它相比agg
和transform
而言更加靈活,可以傳入任意自定義的函數,實現複雜的數據操做。在Pandas數據處理三板斧——map、apply、applymap詳解
)中,介紹了apply
的使用,那在groupby
後使用apply
和以前所介紹的有什麼區別呢?
區別是有的,可是整個實現原理是基本一致的。二者的區別在於,對於groupby
後的apply
,以分組後的子DataFrame
做爲參數傳入指定函數的,基本操做單位是DataFrame
,而以前介紹的apply
的基本操做單位是Series
。仍是以一個案例來介紹groupby
後的apply
用法。
假設我如今須要獲取各個公司年齡最大的員工的數據,該怎麼實現呢?能夠用如下代碼實現:
In [38]: def get_oldest_staff(x): ...: df = x.sort_values(by = 'age',ascending=True) ...: return df.iloc[-1,:] ...: In [39]: oldest_staff = data.groupby('company',as_index=False).apply(get_oldest_staff) In [40]: oldest_staff Out[40]: company salary age 0 A 23 33 1 B 21 40 2 C 43 35
這樣便獲得了每一個公司年齡最大的員工的數據,整個流程圖解以下:
能夠看到,此處的apply
和上篇文章中所介紹的做用原理基本一致,只是傳入函數的參數由Series
變爲了此處的分組DataFrame
。
最後,關於apply
的使用,這裏有個小建議,雖說apply
擁有更大的靈活性,但apply
的運行效率會比agg
和transform
更慢。因此,groupby
以後能用agg
和transform
解決的問題仍是優先使用這兩個方法,實在解決不了了才考慮使用apply
進行操做。
掃碼關注公衆號「Python讀財」,第一時間獲取乾貨,還能夠加Python學習交流羣!!