Pandas系列(九)-分組聚合詳解

目錄python

  • 1. 將對象分割成組
  • 1.1 關閉排序
  • 1.2 選擇列
  • 1.3 遍歷分組
  • 1.4 選擇一個組
  • 2. 聚合
  • 2.1 一次應用多個聚合操做
  • 2.2 對DataFrame列應用不一樣的聚合操做
  • 3. transform 操做
  • 4. apply 操做

數據準備

# 導入相關庫
import numpy as np
import pandas as pd
index = pd.Index(data=["Tom", "Bob", "Mary", "James", "Andy", "Alice"], name="name")
data = {
    "age": [18, 30, 35, 18, np.nan, 30],
    "city": ["Bei Jing ", "Shang Hai ", "Guang Zhou", "Shen Zhen", np.nan, " "],
    "sex": ["male", "male", "female", "male", np.nan, "female"],
    "income": [3000, 8000, 8000, 4000, 6000, 7000]
}
user_info = pd.DataFrame(data=data, index=index)
user_info
Out[59]: 
        age        city     sex  income
name                                   
Tom    18.0   Bei Jing     male    3000
Bob    30.0  Shang Hai     male    8000
Mary   35.0  Guang Zhou  female    8000
James  18.0   Shen Zhen    male    4000
Andy    NaN         NaN     NaN    6000
Alice  30.0              female    7000

1.將對象分割成組

  在進行分組統計前,首先要作的就是進行分組。既然是分組,就須要依賴於某個信息。好比,依據性別來分組。直接調用 user_info.groupby(user_info["sex"])便可完成按照性別分組。數組

grouped  = user_info.groupby(user_info["sex"])
grouped.groups
Out[60]: 
{'female': Index(['Mary', 'Alice'], dtype='object', name='name'),
 'male': Index(['Tom', 'Bob', 'James'], dtype='object', name='name')}
#能夠看到,已經可以正確的按照性別來進行分組了。一般咱們爲了更簡單,會使用這種方式來實現相同的功能:user_info.groupby("sex") 
grouped = user_info.groupby('sex')
grouped.groups
Out[61]: 
{'female': Index(['Mary', 'Alice'], dtype='object', name='name'),
 'male': Index(['Tom', 'Bob', 'James'], dtype='object', name='name')}
#先按性別分組,後按年齡分組
grouped  = user_info.groupby(["sex", "age"])
grouped.groups
Out[62]: 
{('male', 18.0): Index(['Tom', 'James'], dtype='object', name='name'),
 ('male', 30.0): Index(['Bob'], dtype='object', name='name'),
 ('female', 35.0): Index(['Mary'], dtype='object', name='name'),
 (nan, nan): Index(['Andy'], dtype='object', name='name'),
 ('female', 30.0): Index(['Alice'], dtype='object', name='name')}

1.1關閉排序

默認狀況下,groupby 會在操做過程當中對數據進行排序。若是爲了更好的性能,能夠設置 sort=False。app

grouped  = user_info.groupby(["sex", "age"], sort=False)
grouped.groups
Out[63]: 
{('male', 18.0): Index(['Tom', 'James'], dtype='object', name='name'),
 ('male', 30.0): Index(['Bob'], dtype='object', name='name'),
 ('female', 35.0): Index(['Mary'], dtype='object', name='name'),
 (nan, nan): Index(['Andy'], dtype='object', name='name'),
 ('female', 30.0): Index(['Alice'], dtype='object', name='name')}

1.2 選擇列

在使用 groupby 進行分組後,可使用切片 [] 操做來完成對某一列的選擇。函數

grouped  = user_info.groupby("sex")
grouped.city #grouped['city']
Out[64]: <pandas.core.groupby.groupby.SeriesGroupBy object at 0x000000BDFE7DA550>

1.3 遍歷分組

在對數據進行分組後,能夠進行遍歷。若是是根據多個字段來分組的,每一個組的名稱是一個元組。性能

grouped  = user_info.groupby("sex")
for name, group in grouped:
    print("name: {}".format(name))
    print("group: {}".format(group))
    print("--------------")
    
name: female
group:         age        city     sex  income
name                                   
Mary   35.0  Guang Zhou  female    8000
Alice  30.0              female    7000
--------------
name: male
group:         age        city   sex  income
name                                 
Tom    18.0   Bei Jing   male    3000
Bob    30.0  Shang Hai   male    8000
James  18.0   Shen Zhen  male    4000
--------------

 按性別和年齡分組spa

grouped  = user_info.groupby(["sex", "age"])
for name, group in grouped:
    print("name: {}".format(name))
    print("group: {}".format(group))
    print("--------------")
    
name: ('female', 30.0)
group:         age city     sex  income
name                            
Alice  30.0       female    7000
--------------
name: ('female', 35.0)
group:        age        city     sex  income
name                                  
Mary  35.0  Guang Zhou  female    8000
--------------
name: ('male', 18.0)
group:         age       city   sex  income
name                                
Tom    18.0  Bei Jing   male    3000
James  18.0  Shen Zhen  male    4000
--------------
name: ('male', 30.0)
group:        age        city   sex  income
name                                
Bob   30.0  Shang Hai   male    8000
--------------

1.4 選擇一個組

分組後,咱們能夠經過 get_group 方法來選擇其中的某一個組。orm

grouped  = user_info.groupby("sex")
grouped.get_group("male")
user_info.groupby(["sex", "age"]).get_group(("male", 18))
Out[67]: 
        age       city   sex  income
name                                
Tom    18.0  Bei Jing   male    3000
James  18.0  Shen Zhen  male    4000 

2. 聚合

  分組的目的是爲了統計,統計的時候須要聚合,因此咱們須要在分完組後來看下如何進行聚合。常見的一些聚合操做有:計數、求和、最大值、最小值、平均值等。想要實現聚合操做,一種方式就是調用 agg 方法。 對象

# 獲取不一樣性別下所包含的人數
grouped = user_info.groupby("sex")
grouped["age"].agg(len)
Out[68]: 
sex
female    2.0
male      3.0
Name: age, dtype: float64
#grouped.age.count()
#grouped.age.size()
# 獲取不一樣性別下包含的最大的年齡
grouped = user_info.groupby("sex")
grouped["age"].agg(np.max)
Out[71]: 
sex
female    35.0
male      30.0
Name: age, dtype: float64
#grouped.age.max()
grouped = user_info.groupby(["sex", "age"])
rs = grouped.agg(len) #grouped.count()
rs
Out[72]: 
             city  income
sex    age               
female 30.0     1       1
       35.0     1       1
male   18.0     2       2
       30.0     1       1

  若是是根據多個鍵來進行聚合,默認狀況下獲得的結果是一個多層索引結構。有兩種方式能夠避免出現多層索引,先來介紹第一種。對包含多層索引的對象調用 reset_index 方法。blog

#避免多層索引
# 方式一
rs.reset_index()
Out[73]: 
      sex   age  city  income
0  female  30.0     1       1
1  female  35.0     1       1
2    male  18.0     2       2
3    male  30.0     1       1

  另一種方式是在分組時,設置參數 as_index=False排序

# 方式二
grouped = user_info.groupby(["sex", "age"], as_index=False)
grouped.agg(len)
Out[74]: 
      sex   age  city  income
0  female  30.0     1       1
1  female  35.0     1       1
2    male  18.0     2       2
3    male  30.0     1       1

  Series 和 DataFrame 都包含了 describe 方法,咱們分組後同樣可使用 describe 方法來查看數據的狀況。

grouped = user_info.groupby("sex")
grouped.describe()
Out[75]: 
         age                         ...    income                        
       count  mean       std   min   ...       25%     50%     75%     max
sex                                  ...                                  
female   2.0  32.5  3.535534  30.0   ...    7250.0  7500.0  7750.0  8000.0
male     3.0  22.0  6.928203  18.0   ...    3500.0  4000.0  6000.0  8000.0
[2 rows x 16 columns]

  2.1 一次應用多個聚合操做

  有時候進行分組後,不僅僅想獲得一個統計結果,有多是多個。好比想統計出不一樣性別下的一個收入的總和和平均值。

grouped = user_info.groupby("sex")
grouped["income"].agg([np.sum, np.mean])
Out[76]: 
          sum  mean
sex                
female  15000  7500
male    15000  5000

   2.2 對DataFrame列應用不一樣的聚合操做

  有時候可能須要對不一樣的列使用不一樣的聚合操做。例如,想要統計不一樣性別下人羣的年齡的均值以及收入的總和。

grouped = user_info.groupby("sex")
grouped.agg({"age": np.mean, "income": np.sum}).rename(columns={"age": "age_mean", "income": "income_sum"})
Out[77]: 
        age_mean  income_sum
sex                         
female      32.5       15000
male        22.0       15000

3.transform 操做

  前面進行聚合運算的時候,獲得的結果是一個以分組名做爲索引的結果對象。雖然能夠指定 as_index=False ,可是獲得的索引也並非元數據的索引。若是咱們想使用原數組的索引的話,就須要進行 merge 轉換。

  transform方法簡化了這個過程,它會把 func 參數應用到全部分組,而後把結果放置到原數組的索引上(若是結果是一個標量,就進行廣播)

# 經過 agg 獲得的結果的索引是分組名
grouped = user_info.groupby("sex")
grouped["income"].agg(np.mean)
Out[78]: 
sex
female    7500
male      5000
Name: income, dtype: int64
# 經過 transform 獲得的結果的索引是原始索引,它會將獲得的結果自動關聯上原始的索引
grouped = user_info.groupby("sex")
grouped["income"].transform(np.mean)
Out[79]: 
name
Tom      5000.0
Bob      5000.0
Mary     7500.0
James    5000.0
Andy        NaN
Alice    7500.0
Name: income, dtype: float64
#能夠看到,經過 transform 操做獲得的結果的長度與原來保持一致。  

4. apply 操做

  除了 transform 操做外,還有更神奇的 apply 操做。
  apply 會將待處理的對象拆分紅多個片斷,而後對各片斷調用傳入的函數,最後嘗試用 pd.concat() 把結果組合起來。func 的返回值能夠是 Pandas 對象或標量,而且數組對象的大小不限。

#使用 apply 來完成上面的聚合
grouped = user_info.groupby("sex")
grouped["income"].apply(np.mean)
Out[80]: 
sex
female    7500.0
male      5000.0
Name: income, dtype: float64
#來看下 apply 不同的用法吧。
#好比想要統計不一樣性別最高收入的前n個值,能夠經過下面這種方式實現。
def f1(ser, num=2):
    return ser.nlargest(num).tolist()
grouped["income"].apply(f1)
Out[82]: 
sex
female    [8000, 7000]
male      [8000, 4000]
Name: income, dtype: object
#另外,若是想要獲取不一樣性別下的年齡的均值,經過 apply 能夠以下實現。
def f2(sex):
    return sex.age.mean()
user_info.groupby('sex').apply(f2)
Out[83]: 
sex
female    32.5
male      22.0
dtype: float64
grouped.apply(f2)
Out[84]: 
sex
female    32.5
male      22.0
dtype: float64
相關文章
相關標籤/搜索