# 導入相關庫 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 """ 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 """
.groupby()拆分數據
該方法提供的是分組聚合步驟中的拆分功能,能根據索引或字段對數據進行分組
DataFrame.groupby(by=None, axis=0, level=None, as_index=True, sort=True, group_keys=True, squeeze=False, **kwargs)
參數解釋:
- by:接收list,string,mapping或generator。用於確定進行分組的依據。無默認
- axis:接收int。表示操作的軸向,默認對列進行操作。默認為0
- level:接收int或者索引名。代表標簽所在級別。默認為None
- as_index:接收boolearn。表示聚合后的聚合標簽是否以DataFrame索引形式輸出。默認為True
- sort:接收boolearn。表示是否對分組依據分組標簽進行排序。默認為True
- group_keys:接收boolearn。表示是否顯示分組標簽的名稱。默認為True
- squeeze:接收boolearn。表示是否在允許的情況下對返回數據進行降維。默認為False
by參數說明
- 如果傳入的是一個函數則對索引進行計算並分組。
- 如果傳入的是一個字典或者Series則字典或者Series的值用來做分組依據。
- 如果傳入一個NumPy數組則數據的元素作為分組依據。
- 如果傳入的是字符串或者字符串列表則使用這些字符串所代表的字段作為分組依據。
常用的描述性統計方法
用groupby方法分組后的結果並不能直接查看,而是被存在內存中,輸出的是內存地址。實際上分組后的數據對象GroupBy類似Series與DataFrame,是pandas提供的一種對象。GroupBy對象常用的描述性統計方法如下

# 根據性別分組,計算收入列各組的平均值 hh = user_info[['sex','income']].groupby('sex') hh.mean()

將對象分割成組
在進行分組統計前,首先要做的就是進行分組
# 依據性別來分組 grouped = user_info.groupby(user_info["sex"]) grouped.groups # 更簡潔的方式: # 依據性別來分組 user_info.groupby("sex").groups # 先按照性別來分組,再按照年齡進一步分組 user_info.groupby(["sex", "age"]).groups
關閉排序
默認情況下,groupby 會在操作過程中對數據進行排序。如果為了更好的性能,可以設置 sort=False
grouped = user_info.groupby(["sex"], sort=False) grouped.groups
選擇列
在使用 groupby 進行分組后,可以使用切片 [] 操作來完成對某一列的選擇
grouped = user_info.groupby("sex") grouped
遍歷分組
在對數據進行分組后,可以進行遍歷
單個字段分組遍歷
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 """
多個字段分組遍歷
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 """
選擇一個組
.get_group ()
分組后,我們可以通過 get_group 方法來選擇其中的某一個組
grouped = user_info.groupby("sex") grouped.get_group("male") user_info.groupby(["sex", "age"]).get_group(("male", 18))
聚合
分組的目的是為了統計,統計的時候需要聚合,所以我們需要在分完組后來看下如何進行聚合。常見的一些聚合操作有:計數、求和、最大值、最小值、平均值等。得到的結果是
一個以分組名作為索引的結果對象。
想要實現聚合操作,一種方式就是調用 agg 方法。
.agg()
DataFrame.agg(func, axis=0, *args, **kwargs)
參數解釋:
- func:接收list、dict、function。表示應用於每行/每列的函數。無默認
- axis:接收0或1。代表操作的軸向。默認為0
# 獲取不同性別下所包含的人數 grouped = user_info.groupby("sex") grouped["age"].agg(len) # 獲取不同性別下包含的最大的年齡 grouped = user_info.groupby("sex") grouped["age"].agg(np.max)
如果是根據多個鍵來進行聚合,默認情況下得到的結果是一個多層索引結構
grouped = user_info.groupby(["sex", "age"]) rs = grouped.agg(len) rs """ city income sex age female 30.0 1 1 35.0 1 1 male 18.0 2 2 30.0 1 1
避免出現多層索引
.reset_index()
對包含多層索引的對象調用 reset_index 方法
rs.reset_index()
參數 as_index=False
在分組時,設置參數 as_index=False
grouped = user_info.groupby(["sex", "age"], as_index=False) grouped["income"].agg(max)
.describe()查看數據情況
Series 和 DataFrame 都包含了 describe 方法,我們分組后一樣可以使用 describe 方法來查看數據的情況。
grouped = user_info.groupby("sex") grouped.describe().reset_index()
一次應用多個聚合操作
得到多個統計結果
有時候進行分組后,不單單想得到一個統計結果,有可能是多個
# 統計出不同性別下的收入的總和和平均值 grouped = user_info.groupby("sex") grouped["income"].agg([np.sum, np.mean]).reset_index()
統計結果重命名
如果想將統計結果進行重命名,可以傳入字典
grouped = user_info.groupby("sex") grouped["income"].agg([np.sum, np.mean]).rename(columns={"sum": "income_sum", "mean": " income_mean"})
對 DataFrame 列應用不同的聚合操作
有時候可能需要對不同的列使用不同的聚合操作
# 統計不同性別下人群的年齡的均值以及收入的總和 grouped.agg({"age": np.mean, "income": np.sum}).rename(columns={"age": "age_mean", "income": "income_sum"}).reset_index()
transform 操作
前面進行聚合運算的時候,得到的結果是一個以分組名作為索引的結果對象。雖然可以指定 as_index=False ,但是得到的索引也並不是元數據的索引。如果我們想使用原數組的索引的話, 就需要進行 merge 轉換
transform 方法簡化了這個過程,它會把 func 參數應用到所有分組,然后把結果放置到原數組的 索引上(如果結果是一個標量,就進行廣播)
# 通過 agg 得到的結果的索引是分組名 grouped = user_info.groupby("sex") grouped["income"].agg(np.mean) # 通過 transform 得到的結果的索引是原始索引,它會將得到的結果自動關聯上原始的索引 grouped = user_info.groupby("sex") grouped["income"].transform(np.mean)
可以看到,通過 transform 操作得到的結果的長度與原來保持一致
apply 操作
apply 會將待處理的對象拆分成多個片段,然后對各片段調用傳入的函數,最后嘗試用pd.concat() 把結果組合起來。func 的返回值可以是 Pandas 對象或標量,並且數組對象的大小不限。
# 使用 apply 來完成上面的聚合 grouped = user_info.groupby("sex") grouped["income"].apply(np.mean) # 統計不同性別最高收入的前 n 個值 def f1(ser, num=2): return ser.nlargest(num).tolist() grouped["income"].apply(f1) # 獲取不同性別下的年齡的均值 def f2(df): return df["age"].mean() grouped.apply(f2)
