pd.crosstab()可快速生成二维频数表,支持行列交换、多级索引、margins汇总、normalize比例转换、values+aggfunc数值聚合及缺失值与类别对齐处理。

用 pd.crosstab() 快速生成二维频数表
pd.crosstab() 是 Pandas 专为分类变量交叉统计设计的函数,比手动 groupby().size() 更简洁、语义更明确。它默认统计两个列之间的联合频数,返回一个 DataFrame,行和列分别是两个输入变量的唯一值。
常见错误是传入非 Series 或长度不一致的数组,会直接报 ValueError: arrays must all be same length。确保传入的是同长度的 Series、list 或一维 ndarray。
- 基础用法:
pd.crosstab(df['gender'], df['region'])—— 行是 gender,列是 region - 交换行列:
pd.crosstab(df['region'], df['gender'])—— 只需调换参数顺序 - 支持多级索引列:传入列表,如
pd.crosstab(df['A'], [df['B'], df['C']]) - 若某组合无数据,默认填 0(无需额外处理)
添加 margins 和 normalize 控制汇总与比例
加 margins=True 会在末行末列自动添加行和列的合计(即 margin totals),适合快速看整体分布;而 normalize 参数能一键转成比例表,但要注意其取值逻辑:
-
normalize=False(默认):原始频数 -
normalize='index':每行加总为 1(行百分比) -
normalize='columns':每列加总为 1(列百分比) -
normalize=True:整个表加总为 1(全局比例)
注意:normalize 返回的是 float64 类型,且小数位可能很长,常需链式调用 .round(3) 或 .mul(100).astype(int) 转百分比整数。
用 values 和 aggfunc 做数值型聚合(不止计数)
默认 pd.crosstab() 只做频数统计,但通过 values + aggfunc 组合,可对第三列数值做任意聚合,比如均值、求和、最大值等。
例如:想看不同 gender × education 组合下的平均收入:
pd.crosstab(
df['gender'],
df['education'],
values=df['income'],
aggfunc='mean'
)
关键约束:
-
values必须是一维数组,且长度与前两个参数一致 -
aggfunc支持字符串(如'sum'、'median')或自定义函数,但不能是需多参数的 lambda(会报TypeError: crosstab() got an unexpected keyword argument 'aggfunc') - 含缺失值时,
aggfunc='mean'默认跳过 NaN;若想保留 NaN 占位,需提前用fillna()处理values
处理缺失值与类别对齐(避免漏行/漏列)
默认情况下,pd.crosstab() 只包含实际出现的类别组合,不会补全所有可能的交叉项。如果需要完整笛卡尔积(比如后续要画热力图或做模型特征),得显式指定 dropna=False 并配合 Categorical 类型。
-
dropna=False:把 NaN 当作一个独立类别参与统计(行/列中会出现NaN标签) - 更稳妥的方式是先将列转为
Categorical并设置完整categories,再传入crosstab—— 这样即使某类别在数据中没出现,也会在结果中留空列/行 - 示例:
df['region'] = pd.Categorical(df['region'], categories=['North','South','East','West'])
这个细节容易被忽略:很多用户发现结果里“缺了一列”,其实是原始数据里该类别根本没出现,又没做强制类别声明。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











