目录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