一、分组模式及其对象1.分组的一般模式分组操作的核心三要素分组依据按什么维度分组如性别、班级、自定义条件数据来源要对哪些列进行计算如身高、寿命、分数操作组内要执行的统计 / 变换如均值、中位数、标准化通用代码模板df.groupby(分组依据)[数据来源].使用操作示例按性别统计身高中位数df pd.read_csv(../data/learn_pandas.csv) df.groupby(Gender)[Height].median()2.分组依据的本质分组依据本质是可对齐的序列 / 列表groupby会按序列的唯一值对行进行分组。1常见分组依据类型列名 / 列名列表最常用# 单维度按性别分组 df.groupby(Gender)[Height].mean() # 多维度按学校性别分组 df.groupby([School, Gender])[Height].mean()布尔序列 / 条件序列# 按体重是否超过均值分组 condition df.Weight df.Weight.mean() df.groupby(condition)[Height].mean()结果会按True/False分成两组。任意序列 / 列表import numpy as np item np.random.choice(list(abc), df.shape[0]) df.groupby(item)[Height].mean()结果会按a/b/c分成三组。多个序列组合# 按「体重条件 随机字母」分组 df.groupby([condition, item])[Height].mean()结果是两个序列的笛卡尔积分组。2分组依据的等价形式传入列名等价于传入该列的 Series# 以下两种写法完全等价 df.groupby([School, Gender])[Height].mean() df.groupby([df[School], df[Gender]])[Height].mean()可以通过drop_duplicates()查看所有组的类别df[[School, Gender]].drop_duplicates()这会列出所有「学校 性别」的唯一组合也就是最终的分组。注groupby的本质是按序列的唯一值分组列名、条件、列表都是序列的不同形式。多维度分组 多个序列的组合组是所有组合的唯一值。通用模式df.groupby(by...)[cols].agg(...)是 pandas 数据分析的核心工具。3.Groupby 对象Groupby 对象的核心属性与方法先创建分组对象gb df.groupby([School, Grade])属性 / 方法作用示例ngroups返回分组的总个数gb.ngroups→ 16groups返回组名 → 组内行索引的字典gb.groups.keys()可查看所有组名size()返回每个组的元素个数gb.size()按组统计行数get_group()传入组名直接提取该组的所有行gb.get_group((Fudan University, Freshman))注意size()在 DataFrame 中是表的总元素数但在groupby对象中是每组的行数这是一个易混点。4.分组的三大操作分组操作根据返回结果的形态分为三类操作类型对应方法返回结果典型场景聚合Aggregationagg()/mean()/median()/size()每组返回单个标量值统计组内均值、中位数、组容量等变换Transformationtransform()每组返回与原行等长的 Series组内标准化、组内填充缺失值等过滤Filteringfilter()返回符合条件的整组行筛选出组均值 80 的班级、组容量 10 的组等三大操作的对应场景示例聚合按性别统计身高的平均值 → 每组返回一个数。变换按季节对温度做组内标准化 → 每行返回一个变换后的值长度与原表一致。过滤筛选出组内数学平均分 80 的班级 → 返回符合条件班级的所有学生行。二、聚合函数1. 内置聚合函数groupby对象上直接定义了大量经过优化的内置聚合函数优先使用速度快、代码简洁。常用函数列表max/min/mean/median/count/all/any/idxmax/idxmin/mad/nunique/skew/quantile/sum/std/var/sem/size/prod基础示例# 1. 按性别分组选取身高列 gb df.groupby(Gender)[Height] # 2. 示例1返回每组最小值的索引idxmin gb.idxmin() # 输出Gender Female→143, Male→199 # 3. 示例2返回每组95%分位数quantile gb.quantile(0.95) # 输出Gender Female→166.8, Male→185.9多列迭代计算当传入多列时函数会按列独立计算gb df.groupby(Gender)[[Height, Weight]] gb.max()结果GenderHeightWeightFemale170.263.0Male193.989.02. 万能聚合方法agg()/aggregate()agg是aggregate的缩写它能解决内置函数无法覆盖的四大问题。1同时使用多个函数传入函数名列表结果列为多级索引列名 × 函数名。gb.agg([sum, idxmax, skew])结果结构行分组键Female/Male列Height/Weight 分别对应 sum/idxmax/skew2为特定列指定特定函数传入字典键 列名值 函数 / 函数列表。gb.agg({ Height: [mean, max], # 身高求均值、最大值 Weight: count # 体重求计数 })结果GenderHeight_meanHeight_maxWeight_countFemale159.19697170.2135Male173.62549193.9543使用自定义函数lambda或自定义函数参数为组内列的 Series必须返回标量。Lambda 计算极差最大值 - 最小值gb.agg(lambda x: x.mean() - x.min())自定义复杂逻辑对比总体均值def my_func(s): # s.name 是列名Height/Weight return High if s.mean() df[s.name].mean() else Low gb.agg(my_func)结果根据组均值是否高于总体均值返回 High/Low。4聚合结果重命名将函数位置改写为元组(新名字, 原函数)灵活定制列名。列表形式重命名多函数gb.agg([ (range, lambda x: x.max()-x.min()), (my_sum, sum) ])字典形式重命名列映射gb.agg({ Height: [(my_func, my_func), sum], Weight: (max, lambda x: x.max()) })注优先使用Groupby 原生函数mean,sum,idxmax等速度经过优化。agg是万能钥匙用列表实现多函数同时计算用字典实现列 - 函数精准匹配用函数 / Lambda 实现自定义逻辑用元组(别名, 函数)实现结果重命名注意点自定义传入函数必须保证返回标量单值。三、变换和过滤1. 变换函数与transform方法1变换的核心定义返回规则变换函数必须返回与原数据 **** 同长度的序列Series/DataFrame。机制“拆分 - 应用 - 合并” 中的 “应用” 阶段将计算结果广播回原数据的每一行保持索引和形状不变。2内置变换函数Groupby 对象支持一系列组内累计变换函数返回同长度的序列函数含义cummax()组内累计最大值cummin()组内累计最小值cumsum()组内累计求和cumprod()组内累计求积cumcount()组内计数从 0 开始示例gb df.groupby(Gender)[[Height, Weight]] gb.cummax().head() # 每组内逐行累计最大值输出结果行数与原表一致每一行展示当前行及之前的最大值。3自定义变换transform方法transform是自定义变换的核心方法传入的函数参数是组内的 Series必须返回同长度的结构。示例分组标准化Z-Score对身高和体重进行组内标准化(x−μ)/σ# gb df.groupby(Gender)[[Height, Weight]] gb.transform(lambda x: (x - x.mean()) / x.std()).head()输入每组的 Height/Weight 序列。输出与原表形状完全一致的标准化结果索引保持不变。4标量广播机制特征工程常用transform不仅可以返回同长序列还可以返回标量结果会自动广播到整个组。这是特征工程中构造组级特征的关键技巧。示例构造组均值特征为每一行添加所在组的身高、体重均值信息# gb df.groupby(Gender)[[Height, Weight]] gb.transform(mean).head()结果结构每行的值是该组性别的整体均值。例如 Female 组的每一行 Height 都会填充为 159.19...Weight 填充为 47.91...。2.组索引与过滤1过滤 vs 索引行过滤索引 / 行过滤对每一行单独判断符合条件的行保留不符合的丢弃。组过滤对整个组判断如果组整体满足条件返回True则该组所有行都保留如果不满足返回False则该组所有行都被丢弃。本质组过滤是行过滤的推广筛选单位从「行」升级为「组」。2filter方法核心用法groupby对象提供filter()方法实现组过滤输入自定义函数或 lambda参数是当前组的完整 DataFrame可以使用所有 DataFrame 方法 / 属性。输出函数必须返回一个布尔值True/False。True保留该组的所有行False丢弃该组的所有行最终结果所有保留组的行拼接成新的 DataFrame。示例保留样本量 100 的组# gb df.groupby(Gender)[[Height, Weight]] gb.filter(lambda x: x.shape[0] 100).head()x.shape[0]获取当前组的行数样本量。逻辑只保留样本量超过 100 的组其余组全部过滤掉。3核心特点函数参数是 DataFrame可以在函数里做复杂统计如均值、标准差、样本量等来决定是否保留该组。结果形状行数可能减少因为丢弃了部分组但列数不变。典型场景过滤掉样本量过小的组避免统计偏差过滤掉组均值 / 方差不符合要求的组只保留满足特定业务条件的组4总结行过滤df[condition]→ 逐行判断组过滤gb.filter(lambda x: ...)→ 逐组判断filter是 pandas 分组三大操作聚合 / 变换 / 过滤之一是处理分组数据的重要工具。四、跨列分组1. apply的引入跨列计算需求比如 BMI 计算需要同时用到Weight和Height两列agg只能逐列聚合无法处理多列联动。返回标量 / Series/DataFrame 灵活适配filter只能返回布尔值transform只能返回同长度序列而apply可以返回任意结构。典型场景分组后基于多列计算复合指标如 BMI、评分公式并返回聚合结果。2. 基础示例分组计算 BMI 均值import pandas as pd def BMI(x): Height x[Height] / 100 # 假设身高单位是厘米转成米 Weight x[Weight] BMI_value Weight / Height**2 return BMI_value.mean() # 按 Gender 分组传入 BMI 函数 gb df.groupby(Gender)[[Height, Weight]] result gb.apply(BMI)结果是一个Series索引为分组键值为每组 BMI 均值。3. 不同返回值类型的结果形态返回类型结果类型索引结构示例效果标量 / 列表Series与agg结果一致分组键作索引每组返回一个值 / 列表如lambda x: 0或lambda x: [0,0]SeriesDataFrame行索引 分组键列索引 Series 索引如pd.Series([0,0], index[a,b])→ 生成列名为a/b的 DataFrameDataFrameDataFrame行索引 分组键 返回 DF 行索引列索引 返回 DF 列索引嵌套层级最多适合返回多维结果4. 三种返回值的代码示例① 标量 / 列表返回gb df.groupby([Gender,Test_Number])[[Height,Weight]] gb.apply(lambda x: 0) # 返回 Series gb.apply(lambda x: [0,0]) # 列表仍被视为标量返回 Series元素为列表② Series 返回gb.apply(lambda x: pd.Series([0,0], index[a,b])) # 结果行索引GenderTest_Number列索引a/b③ DataFrame 返回import numpy as np gb.apply(lambda x: pd.DataFrame( np.ones((2,2)), index[a,b], columnspd.MultiIndex.from_tuples([(w,x),(y,z)]) )) # 结果行索引GenderTest_Numbera/b列索引多级(w/x, y/z)注返回标量→ 结果是Series结构最简洁。返回 Series→ 结果是DataFrame列由 Series 索引决定。返回 DataFrame→ 结果是多级索引 DataFrame行 / 列都会嵌套。apply是处理跨列分组计算的核心工具尤其适合需要多列联动的复杂逻辑