Pandas教程 | 超好用的Groupby用法詳解


在日常的數據分析中,經常需要將數據根據某個(多個)字段划分為不同的群體(group)進行分析,如電商領域將全國的總銷售額根據省份進行划分,分析各省銷售額的變化情況,社交領域將用戶根據畫像(性別、年齡)進行細分,研究用戶的使用情況和偏好等。在Pandas中,上述的數據處理操作主要運用groupby完成,這篇文章就介紹一下groupby的基本原理及對應的aggtransformapply操作。

為了后續圖解的方便,采用模擬生成的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)
})

 

一、Groupby的基本原理

在pandas中,實現分組操作的代碼很簡單,僅需一行代碼,在這里,將上面的數據集按照company字段進行划分:

In [5]: group = data.groupby("company")

將上述代碼輸入ipython后,會得到一個DataFrameGroupBy對象

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之后的一系列操作(如aggapply等),均是基於子DataFrame的操作。理解了這點,也就基本摸清了Pandas中groupby操作的主要原理。下面來講講groupby之后的常見操作。

二、agg 聚合操作

聚合操作是groupby后非常常見的操作,會寫SQL的朋友對此應該是非常熟悉了。聚合操作可以用來求和、均值、最大值、最小值等,下面的表格列出了Pandas中常見的聚合操作。

針對樣例數據集,如果我想求不同公司員工的平均年齡和平均薪水,可以按照下方的代碼進行:

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

 

如果想對針對不同的列求不同的值,比如要計算不同公司員工的平均年齡以及薪水的中位數,可以利用字典進行聚合操作的指定:

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

transform是一種什么數據操作?和agg有什么區別呢?為了更好地理解transformagg的不同,下面從實際的應用場景出發進行對比。

在上面的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

 

還是以圖解的方式來看看進行groupbytransform的實現過程(為了更直觀展示,圖中加入了company列,實際按照上面的代碼只有salary列):

圖中的大方框是transformagg所不一樣的地方,對agg而言,會計算得到ABC公司對應的均值並直接返回,但對transform而言,則會對每一條數據求得相應的結果,同一組內的樣本會有相同的值,組內求完均值后會按照原索引的順序返回結果,如果有不理解的可以拿這張圖和agg那張對比一下。

四、apply

apply應該是大家的老朋友了,它相比aggtransform而言更加靈活,能夠傳入任意自定義的函數,實現復雜的數據操作。在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的運行效率會比aggtransform更慢。所以,groupby之后能用aggtransform解決的問題還是優先使用這兩個方法,實在解決不了了才考慮使用apply進行操作。

相關文章:

  1. Pandas數據處理三板斧——map、apply、applymap詳解
  2. Pandas數據分析——Merge數據拼接圖文詳解
  3. Pandas數據處理——玩轉時間序列數據
  4. Pandas數據處理——盤點那些常用的函數(上)
  5. Pandas數據處理——盤點那些常用的函數(下)
  6. 天秀!Pandas還能用來寫爬蟲?
  7. 提高數據的顏值!一起看看Pandas中的那些Style
  8. 提速百倍的Pandas性能優化方法,讓你的Pandas飛起來!

 轉自https://zhuanlan.zhihu.com/p/101284491?utm_source=wechat_session


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM