Python--DataFrame分組-GroupBy


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
View Code

如何對 ‘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
View Code

有如下數據

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 相加求平均 . 長沙的也一樣
View Code

那又 如何對整個 dfkey1 分組求平均值

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
View Code

如何求分組大小組數量分組的行數

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
View Code

如何將 groupby() 之后的對象做成一個字典呢?👉 dict()

dict([('a','b'),('c','d')])

 

 dfkey1 分組后的內容轉換

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
View Code

 

上面都是對 列 進行分組的, ‘行’ 可不可以呢?  怎么實現?

# 按行的數據 , 對列進行分組  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}
View Code

按照 分組鍵 ,對整個對象進行分組

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
View Code

# 👆 選取一組列的時候 ,用列表的方式,返回的是 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
View Code

 

 

 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])
View Code

# 通過 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

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


免責聲明!

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



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