Pandas pd.crosstab() 函数
pd.crosstab() 是 Pandas 库中用于计算交叉表(Cross Tabulation)的函数。它可以计算两个或多个变量的频次或聚合统计,生成类似 Excel 数据透视表的表格。
交叉表是统计分析中非常有用的工具,常用于分析两个或多个分类变量之间的关系,例如统计不同部门的男女员工数量。
单词释义: crosstab 是 "cross tabulation"(交叉表)的缩写,是一种统计表格,展示两个或多个变量的联合分布。
基本语法与参数
pd.crosstab() 是 Pandas 库的顶级函数,用于计算交叉表。
语法格式
pd.crosstab(index, columns, values=None, aggfunc=None, margins=False, margins_name='All', dropna=True, normalize=False)
参数说明
- 参数:
index- 类型: 数组-like、Series 或列表。
- 描述: 用作行索引的数据。可以是单个列或多个列(列表)。
- 参数:
columns- 类型: 数组-like、Series 或列表。
- 描述: 用作列索引的数据。可以是单个列或多个列(列表)。
- 参数:
values- 类型: 数组-like 或 None。
- 描述: 要聚合的值。如果指定,则需要配合
aggfunc参数使用。
- 参数:
aggfunc- 类型: 函数或字符串。
- 描述: 聚合函数(如 'sum', 'mean', 'count' 等)。当指定
values时需要使用。
- 参数:
margins- 类型: 布尔值。
- 描述: 如果为
True,添加行列合计。默认为False。
- 参数:
normalize- 类型: 布尔值或 'all', 'index', 'columns'。
- 描述: 如果为
True,将值除以总计,生成比例(0-1)。也可以指定 'index' 或 'columns' 按行或按列归一化。
函数说明
- 返回值: 返回一个 DataFrame,表示两个或多个变量之间的交叉关系。
- 效果: 生成一个表格,行和列分别代表不同的分类变量,单元格显示对应的频次或聚合值。
实例
让我们通过一系列从简单到复杂的例子,彻底掌握 pd.crosstab() 的用法。
示例 1:基础用法 - 两个分类变量的交叉表
实例
import pandas as pd
# 1. 创建员工数据
employees = pd.DataFrame({
'department': ['Sales', 'Sales', 'Sales', 'Engineering', 'Engineering', 'HR', 'HR', 'Sales', 'Engineering', 'HR'],
'gender': ['Male', 'Female', 'Female', 'Male', 'Male', 'Female', 'Male', 'Female', 'Female', 'Male']
})
print("=== 员工数据 ===")
print(employees)
# 2. 计算部门与性别的交叉表(频次)
result = pd.crosstab(employees['department'], employees['gender'])
print("n=== pd.crosstab() 部门与性别交叉表 ===")
print(result)
# 1. 创建员工数据
employees = pd.DataFrame({
'department': ['Sales', 'Sales', 'Sales', 'Engineering', 'Engineering', 'HR', 'HR', 'Sales', 'Engineering', 'HR'],
'gender': ['Male', 'Female', 'Female', 'Male', 'Male', 'Female', 'Male', 'Female', 'Female', 'Male']
})
print("=== 员工数据 ===")
print(employees)
# 2. 计算部门与性别的交叉表(频次)
result = pd.crosstab(employees['department'], employees['gender'])
print("n=== pd.crosstab() 部门与性别交叉表 ===")
print(result)
运行结果预期:
=== 员工数据 === department gender 0 Sales Male 1 Sales Female 2 Sales Female 3 Engineering Male 4 Engineering Male 5 HR Female 6 HR Male 7 Sales Female 8 Engineering Female 9 HR Male === pd.crosstab() 部门与性别交叉表 === gender Female Male department Engineering 1 2 HR 1 2 Sales 3 1
代码解析:
- 结果表格展示了每个部门中男性和女性的员工数量。
示例 2:添加行列合计和归一化
使用 margins 参数可以添加合计,normalize 参数可以查看比例分布。
实例
import pandas as pd
# 使用上面的员工数据
employees = pd.DataFrame({
'department': ['Sales', 'Sales', 'Sales', 'Engineering', 'Engineering', 'HR', 'HR', 'Sales', 'Engineering', 'HR'],
'gender': ['Male', 'Female', 'Female', 'Male', 'Male', 'Female', 'Male', 'Female', 'Female', 'Male']
})
# 1. 添加行列合计
result_margins = pd.crosstab(employees['department'], employees['gender'], margins=True)
print("=== 添加合计 (margins=True) ===")
print(result_margins)
# 2. 归一化 - 转换为比例
print("n=== 整体归一化 (normalize=True) ===")
result_norm = pd.crosstab(employees['department'], employees['gender'], normalize=True)
print(result_norm.round(3))
# 3. 按行归一化(每行加和为 1)
print("n=== 按行归一化 (normalize='index') ===")
result_norm_index = pd.crosstab(employees['department'], employees['gender'], normalize='index')
print(result_norm_index.round(3))
# 4. 按列归一化(每列加和为 1)
print("n=== 按列归一化 (normalize='columns') ===")
result_norm_col = pd.crosstab(employees['department'], employees['gender'], normalize='columns')
print(result_norm_col.round(3))
# 使用上面的员工数据
employees = pd.DataFrame({
'department': ['Sales', 'Sales', 'Sales', 'Engineering', 'Engineering', 'HR', 'HR', 'Sales', 'Engineering', 'HR'],
'gender': ['Male', 'Female', 'Female', 'Male', 'Male', 'Female', 'Male', 'Female', 'Female', 'Male']
})
# 1. 添加行列合计
result_margins = pd.crosstab(employees['department'], employees['gender'], margins=True)
print("=== 添加合计 (margins=True) ===")
print(result_margins)
# 2. 归一化 - 转换为比例
print("n=== 整体归一化 (normalize=True) ===")
result_norm = pd.crosstab(employees['department'], employees['gender'], normalize=True)
print(result_norm.round(3))
# 3. 按行归一化(每行加和为 1)
print("n=== 按行归一化 (normalize='index') ===")
result_norm_index = pd.crosstab(employees['department'], employees['gender'], normalize='index')
print(result_norm_index.round(3))
# 4. 按列归一化(每列加和为 1)
print("n=== 按列归一化 (normalize='columns') ===")
result_norm_col = pd.crosstab(employees['department'], employees['gender'], normalize='columns')
print(result_norm_col.round(3))
运行结果预期:
=== 添加合计 (margins=True) === gender Female Male All department Engineering 1 2 3 HR 1 2 3 Sales 3 1 4 All 5 5 10 === 整体归一化 (normalize=True) === gender Female Male department Engineering 0.1 0.2 HR 0.1 0.2 Sales 0.3 0.1 === 按行归一化 (normalize='index') === gender Female Male department Engineering 0.333 0.667 HR 0.333 0.667 Sales 0.75 0.25 === 按列归一化 (normalize='columns') === gender Female Male department Engineering 0.2 0.4 HR 0.2 0.4 Sales 0.6 0.2
代码解析:
- 归一化方便分析比例关系,了解各部门中性别的相对分布。
- 按行归一化显示每个部门中性别的百分比分布。
- 按列归一化显示每个性别在各部门的分布比例。
示例 3:多个变量和聚合函数
可以使用多个行/列变量,并使用聚合函数计算统计值。
实例
import pandas as pd
import numpy as np
# 1. 创建销售数据
sales = pd.DataFrame({
'region': ['North', 'North', 'South', 'South', 'East', 'East', 'West', 'West', 'North', 'South'],
'product': ['A', 'B', 'A', 'B', 'A', 'B', 'A', 'B', 'B', 'A'],
'quarter': ['Q1', 'Q1', 'Q1', 'Q1', 'Q2', 'Q2', 'Q2', 'Q2', 'Q2', 'Q2'],
'sales': [100, 150, 200, 180, 120, 160, 190, 170, 140, 210]
})
print("=== 销售数据 ===")
print(sales)
# 2. 使用多个行变量
print("n=== 区域和产品的交叉表(频次)===")
result_multi = pd.crosstab([sales['region'], sales['product']], sales['quarter'])
print(result_multi)
# 3. 使用 values 和 aggfunc 计算销售额
print("n=== 区域和季度的销售额合计 ===")
result_sum = pd.crosstab(sales['region'], sales['quarter'], values=sales['sales'], aggfunc='sum')
print(result_sum)
# 4. 计算平均销售额
print("n=== 区域和季度的平均销售额 ===")
result_mean = pd.crosstab(sales['region'], sales['quarter'], values=sales['sales'], aggfunc='mean')
print(result_mean.round(1))
import numpy as np
# 1. 创建销售数据
sales = pd.DataFrame({
'region': ['North', 'North', 'South', 'South', 'East', 'East', 'West', 'West', 'North', 'South'],
'product': ['A', 'B', 'A', 'B', 'A', 'B', 'A', 'B', 'B', 'A'],
'quarter': ['Q1', 'Q1', 'Q1', 'Q1', 'Q2', 'Q2', 'Q2', 'Q2', 'Q2', 'Q2'],
'sales': [100, 150, 200, 180, 120, 160, 190, 170, 140, 210]
})
print("=== 销售数据 ===")
print(sales)
# 2. 使用多个行变量
print("n=== 区域和产品的交叉表(频次)===")
result_multi = pd.crosstab([sales['region'], sales['product']], sales['quarter'])
print(result_multi)
# 3. 使用 values 和 aggfunc 计算销售额
print("n=== 区域和季度的销售额合计 ===")
result_sum = pd.crosstab(sales['region'], sales['quarter'], values=sales['sales'], aggfunc='sum')
print(result_sum)
# 4. 计算平均销售额
print("n=== 区域和季度的平均销售额 ===")
result_mean = pd.crosstab(sales['region'], sales['quarter'], values=sales['sales'], aggfunc='mean')
print(result_mean.round(1))
运行结果预期:
=== 销售数据 ===
region product quarter sales
0 North A Q1 100
1 North B Q1 150
2 South A Q1 200
3 South B Q1 180
4 East A Q2 120
5 East B Q2 160
6 West A Q2 190
7 West B Q2 170
8 North B Q2 140
9 South A Q2 210
=== 区域和产品的交叉表(频次)===
quarter Q1 Q2
region product
East A 0 1
B 0 1
North A 1 0
B 1 1
South A 1 1
B 1 0
West A 0 1
B 0 1
=== 区域和季度的销售额合计 ===
quarter Q1 Q2
region
East NaN 280
North 250 140
South 380 210
West NaN 360
=== 区域和季度的平均销售额 ===
quarter Q1 Q2
region
East NaN 140.0
North 125.0 140.0
South 190.0 210.0
West NaN 180.0
代码解析:
- 使用多个行变量(列表形式)可以创建多层索引的交叉表。
- 每个单元格显示特定区域和产品组合在特定季度的出现次数。
- 使用 values 和 aggfunc 参数可以计算实际数值的聚合(求和、平均等)。
示例 4:处理缺失值
dropna 参数控制是否包含缺失类别。
实例
import pandas as pd
import numpy as np
# 1. 包含缺失值的数据
data = pd.DataFrame({
'A': ['a', 'a', 'b', np.nan, 'a', 'b'],
'B': ['x', 'y', 'x', 'x', np.nan, 'y']
})
print("=== 包含缺失值的数据 ===")
print(data)
# 2. 默认移除包含缺失值的组合
result_drop = pd.crosstab(data['A'], data['B'])
print("n=== 默认移除缺失值 (dropna=True) ===")
print(result_drop)
# 3. 包含缺失类别
result_keep = pd.crosstab(data['A'], data['B'], dropna=False)
print("n=== 包含缺失类别 (dropna=False) ===")
print(result_keep)
import numpy as np
# 1. 包含缺失值的数据
data = pd.DataFrame({
'A': ['a', 'a', 'b', np.nan, 'a', 'b'],
'B': ['x', 'y', 'x', 'x', np.nan, 'y']
})
print("=== 包含缺失值的数据 ===")
print(data)
# 2. 默认移除包含缺失值的组合
result_drop = pd.crosstab(data['A'], data['B'])
print("n=== 默认移除缺失值 (dropna=True) ===")
print(result_drop)
# 3. 包含缺失类别
result_keep = pd.crosstab(data['A'], data['B'], dropna=False)
print("n=== 包含缺失类别 (dropna=False) ===")
print(result_keep)
运行结果预期:
=== 包含缺失值的数据 ===
A B
0 a x
1 a y
2 b x
3 NaN x
4 a NaN
5 b y
=== 默认移除缺失值 (dropna=True) ===
B x y
A
a 1 1
b 1 1
=== 包含缺失值 (dropna=False) ===
B x y NaN
A
a 1 1 1
b 1 1 0
NaN 1 0 0
代码解析:
- 默认
dropna=True会移除包含缺失值的行和列,只显示有效数据。 - 使用
dropna=False可以查看包含缺失值的组合频次。
提示:
pd.crosstab()适合分析分类变量之间的关系。如果需要更复杂的数据汇总(如计算多个聚合指标),请使用pd.pivot_table()函数。

Pandas 常用函数