
本教程旨在详细阐述如何利用Pandas的pivot_table功能,结合CategoricalDtype和数据预处理技巧,生成包含所有列组合子总计的多级标题DataFrame。文章将逐步指导读者创建包含“all”类别(代表所有分组的总和)的复杂透视表,从而满足在数据分析中对多维度聚合和子总计的展示需求。
在数据分析中,我们经常需要对数据进行多维度聚合,并同时查看各个维度的子总计。Pandas的pivot_table是一个强大的工具,但它默认只对现有数据进行聚合。当我们需要在透视表中为每个维度(例如,主题、动物、颜色)引入一个代表“所有类别”的总计列时,直接使用pivot_table会遇到挑战。本教程将介绍一种有效的方法,通过巧妙地结合分类数据类型(CategoricalDtype)和数据预处理,实现包含所有组合子总计的复杂多级透视表。
假设我们有一个包含日期、主题、动物、颜色和数值的数据集,如下所示:
| date | subject | animal | colors | value |
|---|---|---|---|---|
| Jan | English | cat | blue | 1 |
| Feb | Chemistry | dog | green | 2 |
我们的目标是创建一个多级列标题的DataFrame,其中包含所有列(subject, animal, colors)的组合,并且每个维度都额外包含一个“all”类别,代表该维度下所有类别的总计。例如,如果subject有2个唯一值,animal有2个唯一值,colors有2个唯一值,那么最终的列组合将是 (2+1) * (2+1) * (2+1) = 27 种。
直接使用pivot_table难以实现这一点,因为它不会自动生成“all”类别并计算其总计。我们需要一种方法来在透视之前准备数据,使其包含这些“all”类别的聚合信息。
解决此问题的关键在于两步:
首先,我们需要导入必要的库并创建示例DataFrame。
import pandas as pd
from itertools import combinations
# 示例数据
data = {
'date': ['Jan', 'Feb'],
'subject': ['English', 'Chemistry'],
'animal': ['cat', 'dog'],
'colors': ['blue', 'green'],
'value': [1, 2]
}
df = pd.DataFrame(data)
# 扩展DataFrame以模拟更多数据点,确保所有组合都有数据
# 否则,如果只有两个数据点,很多组合会是空的
df = pd.DataFrame({
'date': ['Jan', 'Jan', 'Feb', 'Feb', 'Jan', 'Feb'],
'subject': ['English', 'English', 'Chemistry', 'Chemistry', 'English', 'Chemistry'],
'animal': ['cat', 'dog', 'cat', 'dog', 'cat', 'dog'],
'colors': ['blue', 'green', 'blue', 'green', 'green', 'blue'],
'value': [1, 2, 3, 4, 5, 6]
})
print("原始DataFrame:")
print(df)
# 定义需要转换为分类类型的列
cols_to_categorize = ['date', 'subject', 'animal', 'colors']
# 为每个列创建CategoricalDtype,并添加'all'类别
cats = {}
for col in cols_to_categorize:
unique_values = list(df[col].unique())
# 确保'all'类别排在最后,以便在透视表中显示时有序
cats[col] = pd.CategoricalDtype(unique_values + ['all'], ordered=True)
df_categorized = df.astype(cats)
print("\n转换为分类类型并添加'all'类别后的DataFrame:")
print(df_categorized.dtypes)解释:
这一步是实现子总计的关键。我们需要创建一系列新的DataFrame,每个DataFrame都代表一个特定分组下的“all”总计。例如,一个DataFrame可能包含所有subject和animal组合下,所有colors的总计。
# 存储所有子总计的列表
data_for_pivot = [df_categorized.copy()] # 包含原始数据
# 遍历所有可能的组合,生成子总计
# 例如,当r=len(cols_to_categorize)-1时,意味着一个维度是'all'
# 当r=len(cols_to_categorize)-2时,意味着两个维度是'all',以此类推
# 我们可以通过迭代r从1到len(cols_to_categorize)来生成所有级别的子总计
for r in range(len(cols_to_categorize)):
# print(f"\n生成 {len(cols_to_categorize)-r} 个维度是'all'的子总计:")
for grp_cols in combinations(cols_to_categorize, r=r):
# 确定哪些列将作为分组键,哪些列将是'all'
grouping_keys = list(grp_cols)
all_cols = [col for col in cols_to_categorize if col not in grouping_keys]
if not grouping_keys: # 如果没有分组键,表示计算所有数据的总计
subtotal_df = df_categorized['value'].agg(['sum']).reset_index()
subtotal_df = subtotal_df.rename(columns={'sum': 'value'})
for col in cols_to_categorize:
subtotal_df[col] = 'all'
else:
# 计算当前分组键下的值总和
subtotal_df = df_categorized.groupby(grouping_keys, as_index=False, observed=True)['value'].sum()
# 将非分组键的列填充为'all'
for col in all_cols:
subtotal_df[col] = 'all'
# 确保subtotal_df的列顺序和类型与原始df_categorized一致
for col in cols_to_categorize:
if col not in subtotal_df.columns:
subtotal_df[col] = 'all' # 如果某个维度完全是'all',则添加该列并赋值'all'
subtotal_df[col] = subtotal_df[col].astype(cats[col])
data_for_pivot.append(subtotal_df[cols_to_categorize + ['value']])
# 合并所有数据和子总计
out_df = pd.concat(data_for_pivot, ignore_index=True)
# 再次确保所有列都是正确的CategoricalDtype
for col in cols_to_categorize:
out_df[col] = out_df[col].astype(cats[col])
print("\n包含所有子总计的预处理DataFrame:")
print(out_df)
print(out_df.dtypes)解释:
现在,我们有了包含所有粒度和子总计信息的out_df,可以使用pivot_table来构建最终的多级报表。
# 使用pivot_table进行最终透视
# index: 作为行索引的列
# columns: 作为列索引的列,将形成多级标题
# values: 聚合的数值列
# aggfunc: 聚合函数,例如'sum', 'median', 'mean'等
# fill_value: 填充没有数据点的单元格的值
# observed=False: 确保pivot_table显示所有CategoricalDtype的类别,包括'all',即使它们在数据中没有实际出现
final_pivot_table = out_df.pivot_table(
index='date',
columns=['subject', 'animal', 'colors'],
values='value',
aggfunc='sum', # 聚合函数可以根据需求选择,例如'median'
fill_value=0, # 填充没有数据的组合,通常用0或NaN
observed=False # 关键参数,确保显示所有分类,包括'all'
)
print("\n最终的多级子总计透视表:")
print(final_pivot_table)解释:
生成的final_pivot_table将是一个具有多级列标题的DataFrame,其中包含所有subject、animal、colors的组合,以及它们各自的“all”子总计。行索引也将包含date的类别及其“all”总计(如果date也被处理为分类并包含'all')。
注意事项:
通过以上步骤,我们成功地利用Pandas的CategoricalDtype、itertools.combinations进行数据预处理,并结合pivot_table的observed=False参数,创建了一个功能强大的多级子总计透视表。这种方法使得在复杂的业务分析中,能够清晰地展示不同维度下的聚合数据及其总计,极大地提升了数据分析的灵活性和洞察力。
以上就是使用Pandas Pivot Table生成多级子总计的教程的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号