排序用于调整数据展示顺序、辅助找极值;聚合用于分组统计,是报表、指标计算的核心。本文把
sort_values、sort_index、rank、groupby、agg、transform、apply整合在一起,延续销售明细数据集。
前置导入
import pandas as pd
import numpy as np
一、示例数据
data = {
"订单号": ["A001", "A002", "A003", "A004", "A005", "A006"],
"商品": ["键盘", "鼠标", "显示器", "键盘", "鼠标", "显示器"],
"数量": [2, 1, 1, 3, 2, 2],
"单价": [89, 45, 1200, 89, 45, 1200],
"下单日期": ["2026-10-01", "2026-10-02", "2026-10-03", "2026-10-04", "2026-10-04", "2026-10-05"]
}
df = pd.DataFrame(data)
df["金额"] = df["数量"] * df["单价"]
二、数据排序 sort_values
sort_values 按字段值排序,最常用
# 单列排序:按金额升序
df_sort1 = df.sort_values(by="金额", ascending=True)
# 多列排序:先按商品,同商品内按金额降序
df_sort2 = df.sort_values(by=["商品", "金额"], ascending=[True, False])
# 缺失值放最前面(na_position="last" 默认放末尾)
df_sort3 = df.sort_values(by="金额", na_position="first")
参数说明:
by:排序字段,支持列表多字段ascending:布尔/布尔列表,对应每一列升降序na_position:first/last,控制NaN位置ignore_index=True:排序后重置行索引(非常推荐,避免索引乱掉)
# 推荐写法,排序后重置索引
df_sort = df.sort_values("金额", ascending=False, ignore_index=True)
三、索引排序 sort_index
按行索引或者列名排序
# 行索引升序
df.sort_index()
# 行索引降序
df.sort_index(ascending=False)
# 对列名排序(横向排列)
df.sort_index(axis=1)
四、排名 rank
排序的衍生功能,计算每条数据在组内的名次
# 金额排名
df["金额排名"] = df["金额"].rank(method="min", ascending=False)
method 选项:
min:并列取最小名次(1,2,2,4)max:并列取最大名次(1,3,3,4)average:并列取平均名次(默认,1,2.5,2.5,4)first:值相同,按原始出现先后排名
五、基础聚合(不分组,全局统计)
直接对整个Series/DataFrame做聚合
# 单个统计
df["金额"].sum()
df["金额"].mean()
df["金额"].max()
df["金额"].min()
df["金额"].count() # 非空数量
df["金额"].median() # 中位数
df["金额"].std() # 标准差
# 一次性多个聚合
df["金额"].agg(["sum", "mean", "max", "min"])
# 多列分别聚合
df[["数量","金额"]].agg(["sum","mean"])
六、groupby 分组 + agg 聚合(核心)
6.1 简单分组
# 按商品分组,金额求和
g = df.groupby("商品")
g["金额"].sum()
6.2 agg 多聚合,自定义结果列名(新版推荐)
agg_result = df.groupby("商品").agg(
订单总数=("订单号", "count"),
销售总数量=("数量", "sum"),
销售总金额=("金额", "sum"),
平均单价=("单价", "mean"),
最大单笔金额=("金额", "max")
).reset_index()
print(agg_result)
reset_index()把分组索引变回普通列,方便后续导出Excel
6.3 同一个字段,多个聚合函数
df.groupby("商品")["金额"].agg(["sum", "mean", "max"])
6.4 多字段分组
# 商品 + 日期双重分组
df.groupby(["商品", "下单日期"]).agg(总金额=("金额","sum")).reset_index()
6.5 as_index 参数
# as_index=False,分组结果直接是普通列,不用reset_index
df.groupby("商品", as_index=False).agg(总金额=("金额","sum"))
七、transform 分组聚合(结果回填到原表)
agg 输出分组汇总行;transform 会保持原DataFrame行数不变,把分组统计值回填到每一行(用来做组内对比)
# 每个商品的总金额,回填到原始每一行
df["商品总金额"] = df.groupby("商品")["金额"].transform("sum")
# 组内均值
df["商品平均金额"] = df.groupby("商品")["金额"].transform("mean")
# 计算单笔占本组总额比例
df["占比"] = df["金额"] / df["商品总金额"]
这个是报表里计算占比、组内排名高频用法。
八、filter 分组过滤(过滤整个分组)
和普通布尔筛选不一样:filter 是按分组整体过滤,满足条件的整个分组保留
# 只保留总金额大于1000的商品分组
df_filter = df.groupby("商品").filter(lambda x: x["金额"].sum() > 1000)
普通筛选:过滤行;filter:过滤整个分组
九、apply 在groupby内自定义聚合
适合复杂逻辑,性能弱,小数据集用
def group_stats(sub_df):
return pd.Series({
"总额": sub_df["金额"].sum(),
"笔数": len(sub_df),
"最大单": sub_df["金额"].max()
})
df.groupby("商品").apply(group_stats)
十、排序 + 聚合 组合实战模板
# 1. 分组汇总
group_df = df.groupby("商品", as_index=False).agg(
总数量=("数量","sum"),
总金额=("金额","sum")
)
# 2. 按总金额降序排序
group_df = group_df.sort_values("总金额", ascending=False, ignore_index=True)
print(group_df)
十一、常用参数速记
| 方法 | 作用 | 特点 |
|---|---|---|
| sort_values | 按值排序 | 最常用,支持多列 |
| sort_index | 按索引排序 | 行/列索引 |
| rank | 组内排名 | 并列名次多种策略 |
| agg | 分组汇总 | 输出少行,统计报表 |
| transform | 分组回填 | 行数不变,用于对比、占比 |
| filter | 分组筛选 | 剔除整个分组,不是单行 |
| apply | 自定义分组逻辑 | 灵活,速度慢 |
十二、避坑清单
- 排序后索引混乱,记得加
ignore_index=True groupby默认会把分组字段变成索引,不想用索引就as_index=False或者reset_index()transform必须保证返回的Series长度和分组子表一致,否则报错- apply 适合复杂逻辑,大数据优先用向量化、transform、agg,不要滥用
- 多列排序时,
ascending列表长度必须和排序字段数量一致 - 字符串排序是字典序,数字字符串排序容易出错,先转数值
0 条笔记