Python数据分析和数据处理库Pandas(数据聚合、转换、过滤函数)
目录
1.通过transform()将每一组的样本数据减去各组的均值,实现数据标准化
一.DataFrameGroupBy对象
对DataFrame对象调用groupby()方法后,会返回DataFrameGroupBy对象。
import pandas as pd
df = pd.read_csv("data/employees.csv") # 读取员工数据
# 按department_id分组,返回DataFrameGroupBy对象
print(df.groupby("department_id"))
运行结果:
![]()
这个对象可以看成是一种特殊形式的 DataFrame,里面隐藏着若干组数据,但是在没有应用累计函数之前不会计算。DataFrameGroupBy对象是一种非常灵活的抽象类型。在大多数场景中,可以将它看成是DataFrame的集合。
1.查看分组
通过groups属性查看分组结果,返回一个字典,字典的键是分组的标签,值是属于该组的所有索引的列表。
import pandas as pd
import numpy as np
df = pd.read_csv("data/employees.csv") # 读取员工数据
print(df.groupby("department_id").groups) # 查看分组结果
部分运行结果:
![]()
这个字典里key值是部门号,value是这个部门里的员工在DataFrame里的索引index。
通过get_group()方法获取分组:
import pandas as pd
import numpy as np
df = pd.read_csv("data/employees.csv") # 读取员工数据
print(df.groupby("department_id").get_group(50)) # 获取分组为50的数据
部分运行结果:

有45个员工属于部门50。第一列数据是在原本的DataFrame里的索引index。
2.按列取值
import pandas as pd
import numpy as np
df = pd.read_csv("data/employees.csv") # 读取员工数据
print(df.groupby("department_id")["salary"])
运行结果:
![]()
这里从原来的DataFrame中取某个列名作为一个Series组,也就是SeriesGroupBy对象。与DataFrameGroupBy对象一样,直到我们运行累计函数,才会开始计算。
我们同样可以对这个SeriesGroupBy对象查看groups属性和调用get_group()方法查看分组,结果与上面对DataFrameGroupBy对象的调用结果一样,都是部门号和索引的映射字典。
import pandas as pd
import numpy as np
df = pd.read_csv("data/employees.csv") # 读取员工数据
print(df.groupby("department_id")["salary"].mean()) # 计算每个部门平均薪资
运行结果:

3.按组迭代
GroupBy对象支持直接按组进行迭代,返回的每一组都是Series或DataFrame。
import pandas as pd
import numpy as np
df = pd.read_csv("data/employees.csv") # 读取员工数据
for dept_id, group in df.groupby("department_id"):
print(f"当前部门id: {dept_id},分组情况:{group.shape}")
print(group.iloc[:, 0:3])
print("----------------------------------------------")
部分运行结果:

4.按多字段分组
import pandas as pd
import numpy as np
df = pd.read_csv("data/employees.csv") # 读取员工数据
# # 按department_id和job_id分组,然后查看平均薪资和平均commission_pct
salary_mean = df.groupby(["department_id", "job_id"])[["salary", "commission_pct"]].mean()
print(salary_mean.index) # 查看分组后的索引
运行结果:

按多个字段分组后得到的索引为复合索引,这里就是department_id和job_id一起作为索引。
import pandas as pd
import numpy as np
df = pd.read_csv("data/employees.csv") # 读取员工数据
# # 按department_id和job_id分组,然后查看平均薪资和平均commission_pct
salary_mean = df.groupby(["department_id", "job_id"])[["salary", "commission_pct"]].mean()
print(salary_mean.columns) # 查看分组后的列
运行结果:
![]()
可通过reset_index()方法重置索引。
import pandas as pd
import numpy as np
df = pd.read_csv("data/employees.csv") # 读取员工数据
# # 按department_id和job_id分组,然后查看平均薪资和平均commission_pct
salary_mean = df.groupby(["department_id", "job_id"])[["salary", "commission_pct"]].mean()
print(salary_mean.reset_index())
运行结果:

也可以在分组的时候通过as_index = False参数(默认是True)重置索引。
import pandas as pd
import numpy as np
df = pd.read_csv("data/employees.csv") # 读取员工数据
# # 按department_id和job_id分组,然后查看平均薪资和平均commission_pct
salary_mean = df.groupby(["department_id", "job_id"], as_index=False)[["salary", "commission_pct"]].mean()
print(salary_mean)
运行结果同上。
5.cut()
pandas.cut()用于将连续数据(如数值型数据)分割成离散的区间。可以使用cut()来将数据划分为不同的类别或范围,通常用于数据的分箱处理。
cut()部分参数说明:
|
参数 |
说明 |
|
x |
要分箱的数组或Series,通常是数值型数据。 |
|
bins |
切分区间的数值列表或者整数。如果是整数,则表示将数据均匀地分成多少个区间。如果是列表,则需要指定每个区间的边界。 |
|
right |
默认True,表示每个区间的右端点是闭区间,即包含右端点。如果设置为False,则左端点为闭区间。 |
|
labels |
传入一个列表指定每个区间的标签。 |
import pandas as pd
import numpy as np
df = pd.read_csv("data/employees.csv") # 加载员工数据
salary = pd.cut(df.iloc[9:16]["salary"], 3)
print(salary)
运行结果:
这里就是用一个区间表示salary,这三个区间就是用工资最小值和最大值的范围平均分成了3分,也就是(3092.1, 5733.333] ,(5733.333, 8366.667] 和(8366.667, 11000.0]。
import pandas as pd
import numpy as np
df = pd.read_csv("data/employees.csv") # 加载员工数据
salary = pd.cut(df.iloc[9:16]["salary"], [0, 10000, 20000])
print(salary)
运行结果:

这里就是指定了区间的边界。
import pandas as pd
import numpy as np
df = pd.read_csv("data/employees.csv") # 加载员工数据
salary = pd.cut(df.iloc[9:16]["salary"], 3, labels=["low", "medium", "high"])
print(salary)
运行结果:

二.分组聚合
df.groupby("分组字段")["要聚合的字段"].聚合函数()
df.groupby(["分组字段", "分组字段2", ...])[["要聚合的字段", "要聚合的字段2", ...]].聚合函数()
1.常用聚合函数
|
方法 |
说明 |
|
sum() |
求和 |
|
mean() |
平均值 |
|
min() |
最小值 |
|
max() |
最大值 |
|
var() |
方差 |
|
std() |
标准差 |
|
median() |
中位数 |
|
quantile() |
指定位置的分位数,如quantile(0.5) |
|
describe() |
常见统计信息 |
|
size() |
所有元素的个数 |
|
count() |
非空元素的个数 |
|
first |
第一行 |
|
last |
最后一行 |
|
nth |
第n行 |
2.一次计算多个统计值
可以通过agg()或aggregate()进行更复杂的操作,如一次计算多个统计值。agg()和aggregate()完全没区别。
import pandas as pd
import numpy as np
df = pd.read_csv("data/employees.csv") # 加载员工数据
# 按department_id分组,计算salary的最小值,中位数,最大值
print(df.groupby("department_id")["salary"].agg(["min", "median", "max"]))
运行结果:

3.多个列计算不同的统计值
也可以在agg()中传入字典,对多个列计算不同的统计值。
import pandas as pd
import numpy as np
df = pd.read_csv("data/employees.csv") # 加载员工数据
# 按department_id分组,统计job_id的种类数,salary的平均值
print(df.groupby("department_id").agg({"job_id": "nunique", "salary": "mean"}))
运行结果:

4.重命名统计值
可以在agg()后通过rename()对统计后的列重命名。
import pandas as pd
import numpy as np
df = pd.read_csv("data/employees.csv") # 加载员工数据
# 按department_id分组,统计job_id的种类数,salary的平均值
print(df.groupby("department_id").agg({"job_id": "nunique", "salary": "mean"}).rename(columns={"job_id": "工种数", "salary": "平均工资"}))
运行结果:

5.自定义函数
可以向agg()中传入自定义函数进行计算。
import pandas as pd
import numpy as np
df = pd.read_csv("data/employees.csv") # 加载员工数据
def f(x):
"""统计每个部门员工last_name的首字母"""
result = set()
for i in x:
result.add(i[0])
return result
print(df.groupby("department_id")["last_name"].agg(f))
运行结果:

三.分组转换
聚合操作返回的是对组内全量数据缩减过的结果,而转换操作会返回一个新的全量数据。数据经过转换之后,其形状与原来的输入数据是一样的。
分组聚合和分组转换的核心区别:
- 聚合:每组返回 1 个值(汇总统计),行数变少(每组一行)。
- 转换:每组返回和原数据一样多行(把计算结果广播回去),行数不变。
1.通过transform()将每一组的样本数据减去各组的均值,实现数据标准化
import pandas as pd
import numpy as np
df = pd.read_csv("data/employees.csv") # 加载员工数据
print(df.groupby("department_id")["salary"].transform(lambda x : x - x.mean()))
运行结果:

2.通过transform()按分组使用平均值填充缺失值
import pandas as pd
import numpy as np
df = pd.read_csv("data/employees.csv") # 加载员工数据
na_index = pd.Series(df.index.tolist()).sample(30) # 随机挑选30条数据
df.loc[na_index, "salary"] = pd.NA # 将这30条数据的salary设置为缺失值
print(df.groupby("department_id")["salary"].agg(["size", "count"]))
def fill_missing(x):
# 使用平均值填充,如果平均值也为NaN,用0填充(也就是这个部门的所有salary都是NaN的基础上)
if np.isnan(x.mean()):
return 0
return x.fillna(x.mean())
df["salary"] = df.groupby("department_id")["salary"].transform(fill_missing)
print(df.groupby("department_id")["salary"].agg(["size", "count"])) # 查看每组数据总数与非空数据数
运行结果:

四.分组过滤
过滤操作可以让我们按照分组的属性丢弃若干数据。
例如,我们可能只需要保留commission_pct不包含空值的分组的数据。
import pandas as pd
import numpy as np
df = pd.read_csv("data/employees.csv") # 加载员工数据
commission_pct_filter = df.groupby("department_id").filter(
lambda x: x["commission_pct"].notnull().all()
)
print(commission_pct_filter)
其中lambda表达式中的参数x表示每个分组的DataFrame。
部分运行结果:

只有部门号80的这一组数据的commission_pct不包含空值,所以只有部门号为80的输出。
更多推荐



所有评论(0)