Pandas 分組操作

2022-08-17 17:16 更新

在數(shù)據(jù)分析中,經(jīng)常會遇到這樣的情況:根據(jù)某一列(或多列)標簽把數(shù)據(jù)劃分為不同的組別,然后再對其進行數(shù)據(jù)分析。比如,某網(wǎng)站對注冊用戶的性別或者年齡等進行分組,從而研究出網(wǎng)站用戶的畫像(特點)。在 Pandas 中,要完成數(shù)據(jù)的分組操作,需要使用 groupby() 函數(shù),它和 SQL 的GROUP BY操作非常相似。 

在劃分出來的組(group)上應用一些統(tǒng)計函數(shù),從而達到數(shù)據(jù)分析的目的,比如對分組數(shù)據(jù)進行聚合、轉(zhuǎn)換,或者過濾。這個過程主要包含以下三步:

  • 拆分(Spliting):表示對數(shù)據(jù)進行分組;
  • 應用(Applying):對分組數(shù)據(jù)應用聚合函數(shù),進行相應計算;
  • 合并(Combining):最后匯總計算結(jié)果。

下面對 groupby() 函數(shù)的應用過程進行具體的講解。

創(chuàng)建DataFrame對象

首先我們創(chuàng)建一個 DataFrame 對象,下面數(shù)據(jù)描述了某班學生,計算機選修課的考試成績:

import pandas as pd 
import numpy as np 
data = {'Name': ['John', 'Helen', 'Sona', 'Ella'], 
   'score': [82, 98, 91, 87], 
   'option_course': ['C#','Python','Java','C']} 
df = pd.DataFrame(data)
print(df)  

輸出結(jié)果:

    Name  score   option_course
0   John     82            C#
1  Helen     98        Python
2   Sona     91          Java
3   Ella     87             C

創(chuàng)建groupby分組對象

使用 groupby() 可以沿著任意軸分組。您可以把分組時指定的鍵(key)作為每組的組名,方法如下所示:

  • df.groupby("key")
  • df.groupby("key",axis=1)
  • df.groupby(["key1","key2"])

通過上述方法對 DataFrame 對象進行分組操作:

import pandas as pd
import numpy as np
data = {'Name': ['John', 'Helen', 'Sona', 'Ella'],
   'score': [82, 98, 91, 87],
   'option_course': ['C#','Python','Java','C']}
df = pd.DataFrame(data)
print(df)
#生成分組groupby對象
print(df.groupby('score'))

輸出結(jié)果:

<pandas.core.groupby.generic.DataFrameGroupBy object at 0x0000021DE9A89640>

查看分組結(jié)果

1) groups查看分組結(jié)果

通過調(diào)用groups屬性查看分組結(jié)果:

import pandas as pd
import numpy as np
data = {'Name': ['John', 'Helen', 'Sona', 'Ella'],
   'score': [82, 98, 91, 87],
   'option_course': ['C#','Python','Java','C']}
df = pd.DataFrame(data)
#查看分組
print(df.groupby('score').groups)

輸出結(jié)果:

{82: Int64Index([0], dtype='int64'), 
87: Int64Index([3], dtype='int64'), 
91: Int64Index([2], dtype='int64'), 
98: Int64Index([1], dtype='int64')}

2) 多個列標簽分組

當然也可以指定多個列標簽進行分組,示例如下:

import pandas as pd
import numpy as np
data = {'Name': ['John', 'Helen', 'Sona', 'Ella'],
   'score': [82, 98, 91, 87],
   'option_course': ['C#','Python','Java','C']}
df = pd.DataFrame(data)
#查看分組
print(df.groupby(['Name','score']).groups)

輸出結(jié)果:

{('Ella', 87): Int64Index([3], dtype='int64'), 
('Helen', 98): Int64Index([1], dtype='int64'), 
('John', 82): Int64Index([0], dtype='int64'), 
('Sona', 91): Int64Index([2], dtype='int64')}

通過 get_group() 方法可以選擇組內(nèi)的具體數(shù)據(jù)項:

import pandas as pd
import numpy as np
data = {'Name': ['John', 'Helen', 'Sona', 'Ella'],
   'score': [82, 98, 91, 87],
   'option_course': ['C#','Python','Java','C']}
df = pd.DataFrame(data)
#根據(jù)score來分組
grouped=df.groupby('score')
#根據(jù)對應組的數(shù)據(jù)值,選擇一個組
print(grouped.get_group(91))

輸出結(jié)果:

   Name  score option_course
2  Sona     91          Java

遍歷分組數(shù)據(jù)

通過以下方法來遍歷分組數(shù)據(jù),示例如下:

import pandas as pd
import numpy as np
data = {'Name': ['John', 'Helen', 'Sona', 'Ella'],
   'score': [82, 98, 91, 87],
   'option_course': ['C#','Python','Java','C']}
df = pd.DataFrame(data)
#查看分組
grouped=df.groupby('score')
for label, option_course in grouped:
#其中key代表分組后字典的鍵,也就是score
    print(label)
#字典對應的值選修的科目
    print(option_course)

輸出結(jié)果:

82
   Name  score   option_course
0  John     82            C#
87
   Name  score   option_course
3  Ella     87             C
91
   Name  score   option_course
2  Sona     91          Java
98
    Name  score  option_course
1  Helen     98        Python

如上所示, groupby 對象的組名稱與 score 中的的元素值一一對應。

應用聚合函數(shù)

當您在創(chuàng)建 groupby 對象時,通過 agg() 函數(shù)可以對分組對象應用多個聚合函數(shù): 

import pandas as pd 
import numpy as np 
data = {'name': ['John', 'Helen', 'Sona', 'Ella'], 
   'score': [82, 98, 91, 87], 
   'option_course': ['C#','Python','Java','C']} 
df = pd.DataFrame(data)
grouped=df.groupby('name')
#應用一個聚合函數(shù)求均值
print(grouped['score']).agg(np.mean)

輸出結(jié)果:

name
Ella     87
Helen    98
John     82
Sona     91
Name: score, dtype: int64

當然,您也可以一次性應有多個聚合函數(shù),示例如下:

import pandas as pd
import numpy as np
data = {'name': ['John', 'Helen', 'Sona', 'Ella'],
   'score': [82, 98, 91, 87],
   'option_course': ['C#','Python','Java','C']}
df = pd.DataFrame(data)
grouped=df.groupby('name')
print(grouped['score'].agg([np.size,np.mean,np.std]))

輸出結(jié)果:

       size  mean  std
name                 
Ella      1    87  NaN
Helen     1    98  NaN
John      1    82  NaN
Sona      1    91  NaN

組的轉(zhuǎn)換操作

在組的行或列上可以執(zhí)行轉(zhuǎn)換操作,最終會返回一個與組大小相同的索引對象。示例如下:

import pandas as pd
import numpy as np
df = pd.DataFrame({'種類':['水果','水果','水果','蔬菜','蔬菜','肉類','肉類'],
                '產(chǎn)地':['朝鮮','中國','緬甸','中國','菲律賓','韓國','中國'],
                '水果':['橘子','蘋果','哈密瓜','番茄','椰子','魚肉','牛肉'],
                '數(shù)量':[3,5,5,3,2,15,9],
                '價格':[2,5,12,3,4,18,20]})
#分組求均值,水果、蔬菜、肉類
#對可執(zhí)行計算的數(shù)值列求均值
print(df.groupby('種類').transform(np.mean))
#transform()直接應用demean,實現(xiàn)去均值操作
demean = lambda arr:arr-arr.mean()
print(df.groupby('種類').transform(demean))
#自定義函數(shù)
# 返回分組的前n行數(shù)據(jù)
def get_rows(df,n): 
     #從1到n行的所有列
    return df.iloc[:n,:]
#分組后的組名作為行索引
print(df.groupby('種類').apply(get_rows,n=1))

輸出結(jié)果:

      數(shù)量         價格
0   4.333333   6.333333
1   4.333333   6.333333
2   4.333333   6.333333
3   2.500000   3.500000
4   2.500000   3.500000
5  12.000000  19.000000
6  12.000000  19.000000

      數(shù)量        價格
0 -1.333333 -4.333333
1  0.666667 -1.333333
2  0.666667  5.666667
3  0.500000 -0.500000
4 -0.500000  0.500000
5  3.000000 -1.000000
6 -3.000000  1.000000

      種類  產(chǎn)地  水果  數(shù)量  價格
種類                     
水果 0  水果  朝鮮  橘子   3   2
肉類 5  肉類  韓國  魚肉  15  18
蔬菜 3  蔬菜  中國  番茄   3   3

組的數(shù)據(jù)過濾操作

通過 filter() 函數(shù)可以實現(xiàn)數(shù)據(jù)的篩選,該函數(shù)根據(jù)定義的條件過濾數(shù)據(jù)并返回一個新的數(shù)據(jù)集。

下面,篩選出參加比賽超過三次的球隊(包含三次):

import pandas as pd
import numpy as np
data = {'Team': ['Riders', 'Riders', 'Devils', 'Devils', 'Kings',
   'kings', 'Kings', 'Kings', 'Riders', 'Royals', 'Royals', 'Riders'],
   'Rank': [1, 2, 2, 3, 3,4 ,1 ,1,2 , 4,1,2],
   'Year': [2014,2015,2014,2015,2014,2015,2016,2017,2016,2014,2015,2017],
   'Points':[874,789,863,663,741,802,756,788,694,701,812,698]}
df = pd.DataFrame(data)
#定義lambda函數(shù)來篩選數(shù)據(jù)
print (df.groupby('Team').filter(lambda x: len(x) >= 3))

輸出結(jié)果:

      Team  Rank  Year  Points
0   Riders     1  2014     874
1   Riders     2  2015     789
4    Kings     3  2014     741
6    Kings     1  2016     756
7    Kings     1  2017     788
8   Riders     2  2016     694
11  Riders     2  2017     698


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號