DataFame分組功能及其他配合使用方法
分組統計 👉 GroupBy
# *.groupby(by=None,axis=0,level=None,as_index=True,sort=True,group_keys=True,squeeze=False,observed=False,**kwargs) # axis=0 行 / 1 列
有這樣一組數據 :

df = pd.DataFrame({ 'key1':['a','a','b','b','a'], 'key2':['one','two','one','two','three'], 'data1':np.random.randn(5), 'data2':np.random.randn(5) }) #-------------------------------# key1 key2 data1 data2 0 a one -0.205263 1.820120 1 a two 0.436864 -1.858459 2 b one 0.695624 1.134222 3 b two 0.281301 1.735320 4 a three 1.040519 0.657742
如何對 ‘key1’ 進行 分組 並求 平均值 ?
ass = df['data1'].groupby(df['key1']) #這是一個分組對象,沒有進行任何計算 ass.mean() # 對"對象" 進行調用方法 # df.groupby('key1').mean() # df[['data1','data2']].groupby('key1').mean()
比較簡單 ,呵 ,那么如何對多個 '字段' 進行分組 ? 要求對 key1 , key2進行分組並計算data2的平均值

df['data2'].groupby([df['key1'],df['key2']]).mean() # 這種分組 只需要將需要的字段放入數組( 也是列表[] )中即可 #---------------------------# key1 key2 a one 1.820120 three 0.657742 two -1.858459 b one 1.134222 two 1.735320 Name: data2, dtype: float64
有如下數據 :
city =Series(['北京','長沙','長沙','北京','北京']) years = Series([2018,2018,2019,2018,2019]) #---------------------------# 0 北京 1 長沙 2 長沙 3 北京 4 北京 dtype: object 0 2018 1 2018 2 2019 3 2018 4 2019 dtype: int64
那么 , 如何用城市 和 年份對 df 進行分組呢?

df['data1'].groupby([city,years]).mean() #----------------------------# 北京 2018 -0.681558 2019 1.580496 長沙 2018 -0.112299 2019 -0.498441 Name: data1, dtype: float64 # 分組的鍵可以是任何長度適當(=len(index))的數組 # 👆 這個就是將分組鍵改成了自定義城市和年份 匹配相同的相加求平均值 ,不匹配的不計算 # 北京的2018相加 求平均 北京2019 相加求平均 . 長沙的也一樣
那又 如何對整個 df 的 key1 分組求平均值?

df.groupby(['key1']).mean() # 👆 自動聚合數值列,忽略 非數值 列 df.groupby(['key1','key2']).mean() # 👆 可以將 列名 作為分組鍵 #----------------------# data1 data2 key1 a 0.424040 0.206468 b 0.488462 1.434771 #----------------------# data1 data2 key1 key2 a one -0.205263 1.820120 three 1.040519 0.657742 two 0.436864 -1.858459 b one 0.695624 1.134222 two 0.281301 1.735320
如何求分組的 大小 ,組數量, 分組的行數 ?
df.groupby('key1').size() # の , 我。。。。。 #-----------------# key1 key2 a one 1 three 1 two 1 b one 1 two 1 dtype: int64
對分組進行迭代 :groupby 對象支持迭代,可以產生一組 二元元組,由 分組名 和 數據塊 組成。代碼如下
for df1 ,df2 in df.groupby(['key1']): print(df1) print(df2) #--------------------------# a key1 key2 data1 data2 0 a one -0.245438 -1.030687 1 a two -0.112299 1.817918 4 a three 1.580496 0.861224 b key1 key2 data1 data2 2 b one -0.498441 -0.946496 3 b two -1.117678 0.129720
# 👆 以key1中的數據分組,分出N元元組,名字是key1中的數據名稱為分組名
# len(df[df['key1'].duplicated()==False]) df的key1列中數據不重復的長度 上面輸出的是 2
還可以在多元分組的基礎上再對 key2 分組 ,如何實現呢? 如下

for (k1,k2),group in df.groupby(['key1','key2']): print(k1,k2) # key1的值, key2的值 print(group) # key1的值+key2的值+后面的數據 同累型a one,a two,b one。。。這種 #------------------------# a one key1 key2 data1 data2 0 a one -0.245438 -1.030687 a three key1 key2 data1 data2 4 a three 1.580496 0.861224 a two key1 key2 data1 data2 1 a two -0.112299 1.817918 b one key1 key2 data1 data2 2 b one -0.498441 -0.946496 b two key1 key2 data1 data2 3 b two -1.117678 0.12972
如何將 groupby() 之后的對象做成一個字典呢?👉 dict()
dict([('a','b'),('c','d')])
將 df 按 key1 分組后的內容轉換 :

ps = dict(list(df.groupby(['key1']))) # # 把分組內容變成一個字典對象,通過健取值,如所有a,所有b print(ps) ps['a'] #取出字典中 的所有 a 組 #-----------------------# {'a': key1 key2 data1 data2 0 a one -0.205263 1.820120 1 a two 0.436864 -1.858459 4 a three 1.040519 0.657742, 'b': key1 key2 data1 data2 2 b one 0.695624 1.134222 3 b two 0.281301 1.735320} key1 key2 data1 data2 0 a one -0.205263 1.820120 1 a two 0.436864 -1.858459 4 a three 1.040519 0.657742
上面都是對 列 進行分組的, ‘行’ 可不可以呢? 怎么實現?

# 按行的數據 , 對列進行分組 axis=1 line = df.groupby(df.dtypes,axis=1) # 行 按數據類型進行分組 dict(list(line)) #--------------------# {dtype('float64'): data1 data2 0 -0.205263 1.820120 1 0.436864 -1.858459 2 0.695624 1.134222 3 0.281301 1.735320 4 1.040519 0.657742, dtype('O'): key1 key2 0 a one 1 a two 2 b one 3 b two 4 a three}
按照 分組鍵 ,對整個對象進行分組
df.groupby(['key1']).sum()
分組后有多列 , 那我如何選擇其中的一列 或者多列 ,我如何得到 data1呢?
# 用列名對 groupby 對象進行索引,就能實現選取部分進行聚合達到目的 有效的提高效率

df.groupby(['key2'])['data1'].sum() # 返回的是一個series對象 df.groupby(['key2'])[['data1','data2']].sum() #返回的是一個DataFrame對象 #--------------------------------------# key2 one 0.490361 three 1.040519 two 0.718165 Name: data1, dtype: float64 data1 data2 key2 —————————————— one 0.490361 2.954342 three 1.040519 0.657742 two 0.718165 -0.123139
# 👆 選取一組列的時候 ,用列表的方式,返回的是 DataFrame 對象
## df['data1'].groupby(df['key1']).mean() 等於 df.groupby(['key1'])['data1'].mean() ##
通過 字典 或者 Series 進行分組
df = DataFrame(np.random.randn(5,5),columns=list('abcde'),index=['長沙','北京','上海','杭州','深圳']) df.loc[2:3,['b','c']] = np.NaN #添加幾個NaN值 # 假設已知列的分組關系,希望根據分組計算列的總和
colors = {'a':'red','b':'red','c':'blue','d':'blue','e':'red','f':'orange'}

dt = df.groupby(colors,axis=1) dt.sum() # 就是對columns 使用colors重命名 同名合並 行的值 橫向sum() #------------------# blue red 長沙 0.994708 0.519499 北京 -1.212472 1.080747 上海 0.472694 0.258676 杭州 -2.339634 0.598021 深圳 -1.938784 1.777040
Series 也有同樣的功能 ,使用方法如下 :
ser = Series(colors) df.groupby(ser,axis=1).sum() # axis =1 列之間相加 red+red+red , blue+blue
還可以通過 自定義函數 進行分組 :
def city_level(self): frist_city = ['北京','上海','深圳'] if self in frist_city: return '一線城市' return '二線城市' df.groupby(city_level,axis=0).sum() # 👆 會在分組鍵上調用一次city_level , 並且會將分組鍵作為參數傳給city_level 返回值作為新的分組名稱
還可以 組合使用,比如對城市分地域 , 所以是這么用的: 傳入的函數和數組使用 ‘[ ]’ 列表的方式 用列表來包裹在一起
ars = ['中部','北方','東方','東方','南方'] df.groupby([city_level,ars]).sum()
對於層次索引 , 如何根據索引的級別 來 分組 :
有這么一組數據 :
columns = pd.MultiIndex.from_arrays([['北京','北京','北京','長沙','長沙'],[1,3,4,1,2]],names=['城市','級別']) dfs = DataFrame(np.random.randn(4,5),columns=columns,index=[2016,2017,2018,2019])
所以這樣: 👇
dfs.groupby(level='城市',axis=1).sum()
# 這個就是按城市 合並sum() 行的值 = 各列相加 北京 1 3 4 相加 ,長沙1 2 相加 #
常用的數據聚合函數(復習並知道)
count、sum、mean、median、std、var、min、max、prod、first、last -- 取到分組之后的每個組的函數運算的值
df.groupby('key1').get_group('a') # 得到某一個分組 #運行前,重置下df 我運行前 前面的df都改動了#
面向 多列的函數應用 -- Agg()
# 一次性應用多個函數計算 #
# 有這么一個數據 # df = DataFrame({ 'a':[1,1,2,2], 'b':np.random.rand(4), 'c':np.random.rand(4), 'd':np.random.rand(4) })
如果我想拿到 [ b , c ,d ] 的 平均值 和 總值 怎么搞? 一次拿到

df.groupby('a').agg(['mean',np.sum])
# 通過 agg 方法,傳入一個列表,列表中的元素就是要作用到 每列 上的方法,可以是 字符串,也可是np的函數 #
還可以傳入 字典 , key 就是columns , value 就是要 作用/使用 的函數
df.groupby('a')['b'].agg({'result':np.mean,'result2':np.sum}) df.groupby('a').agg([('res1','mean'),('res2',np.sum)])
dfn.groupby('a').agg(res1=np.mean,res2=np.sum) # 如果運行錯誤,原因是pandas的版本未更新,重新安裝一下就好了 # 通過二元元組列表指定列名 # 指定列名的時候,會形成層次化的索引 # df已更改,所以值和上面的對不上,使用方法是對的,###官方以后會改方法,我運行出警告了###
如何對不同的 列 ,進行不同的函數 :
df.groupby('a').agg({'b':['mean',np.sum],'c':np.std,'d':'max'}) # 面向列的多函數應用
數據分組轉換 👇
有如下數據 :
df = DataFrame({ 'data1':np.random.rand(5), 'data2':np.random.rand(5), 'key1':list('AABBD'), 'key2':['One','Two','One','Two','Four'] })
那么問題來了,如何為df 添加用於存放個索引分組平均值列 mean_*
# 方法一 : 先聚合,在合並
means = df.groupby('key1').mean().add_prefix('mean_') #.add_prefix('**_') 給列名添加前綴
# 合並 merge() pd.merge(df,key1,left_on='key1',right_index=True) # 默認按分組排序 left_on 是列 l/r_index 是索引
# 方法二 : 通過 transform()
dms = df.groupby('key1').transform(np.mean).add_prefix('mean_') df.join(dms) # dms 有對應索引 所以 join 會匹配索引合並
👆 transform 會將一個函數應用到各個分組, 然后將結果放在合適的位置上 。
df.groupby('key1').apply(lambda x:x.describe()) # 對每個分組都進行計算,包括count,mean,std,min,max等等
# 👆 數據重新生成的#
apply() :
傳入的第一個參數是 函數 , apply方法會將分組(groupby后)的每一個片段作為參數傳入函數 。返回結果,最后嘗試將各個結果運行組合到一起,也就是函數運行后的結果組合到一起。
def f_df1(d,m): return (d.sort_index()[:m]) #DataFrame排序后按索引選前m行數據 def f_df2(d,k1): return (d[k1]) # 選擇DataFrame的k1列,結果為Series,層次化索引
dfs.groupby('key1').apply(f_df1,2) # 返回分組'key1'排序后的每組前2行 dfs.groupby('key1').apply(f_df2,'data2') # 返回分組后表的k1列,也就是data2.結果為Series
# dfs 原數據 data1 data2 key1 key2 0 0.363747 0.581347 A One 1 0.982338 0.193684 A Two 2 0.872498 0.377703 B One 3 0.242360 0.946317 B Two 4 0.976749 0.395238 D Four