目錄python
# 導入相關庫 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
在進行分組統計前,首先要作的就是進行分組。既然是分組,就須要依賴於某個信息。好比,依據性別來分組。直接調用 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')}
默認狀況下,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')}
在使用 groupby 進行分組後,可使用切片 [] 操做來完成對某一列的選擇。函數
grouped = user_info.groupby("sex")
grouped.city #grouped['city']
Out[64]: <pandas.core.groupby.groupby.SeriesGroupBy object at 0x000000BDFE7DA550>
在對數據進行分組後,能夠進行遍歷。若是是根據多個字段來分組的,每一個組的名稱是一個元組。性能
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
--------------
分組後,咱們能夠經過 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
分組的目的是爲了統計,統計的時候須要聚合,因此咱們須要在分完組後來看下如何進行聚合。常見的一些聚合操做有:計數、求和、最大值、最小值、平均值等。想要實現聚合操做,一種方式就是調用 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]
有時候進行分組後,不僅僅想獲得一個統計結果,有多是多個。好比想統計出不一樣性別下的一個收入的總和和平均值。
grouped = user_info.groupby("sex")
grouped["income"].agg([np.sum, np.mean])
Out[76]:
sum mean
sex
female 15000 7500
male 15000 5000
有時候可能須要對不一樣的列使用不一樣的聚合操做。例如,想要統計不一樣性別下人羣的年齡的均值以及收入的總和。
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
前面進行聚合運算的時候,獲得的結果是一個以分組名做爲索引的結果對象。雖然能夠指定 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 操做獲得的結果的長度與原來保持一致。
除了 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