You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python实现交叉表类别总计并添加年度状态总计的问题

为Pandas交叉表添加年份状态总计行的解决方案

我用以下Python代码生成随机数据并计算交叉表,已经为交叉表添加了列总计(Total列):

import random 
import pandas as pd

# List of years 
years = [2000, 2001, 2003]

# List of categories and statuses 
categories = ['CatA', 'CatB', 'CatC'] 
statuses = ['Active', 'Inactive']

# Empty lists to store the data 
data = []

# Generate random data for each year 
for year in years:
        for _ in range(3):
            category = random.choice(categories)
            status = random.choice(statuses)
            data.append([year, category, status])

# Create a DataFrame to store the data 
df = pd.DataFrame(data, columns=['Year', 'Category', 'Status'])


#Create crosstab 
cross_tab = pd.crosstab([df.Year, df.Status], df.Category)

#Sum columns 
category_totals = cross_tab.sum(axis=1) 
cross_tab = pd.concat([category_totals, cross_tab], axis=1) 
cross_tab.rename(columns={0: 'Total'}, inplace=True)

#Print 
cross_tab

现在我希望为每个年份添加对应的状态总计行,期望效果如下:

YearStatusTotalCatACatBCatC
2000Total3111
Active2101
Inactive1010
2001Total3210
Active1100
Inactive2110
2003Total3021
Active1001
Inactive2020

我通过year_totals = cross_tab.sum(level="Year")计算出了状态总计数据,但使用pd.concat()合并两个DataFrame时,因索引层级不同失败,请问该如何解决?


解决思路

问题核心是总计行的索引为单层(仅Year),而原交叉表是双层索引(Year+Status),结构不匹配导致合并失败。需要先将总计行的索引转换为双层结构,再合并后重新排序索引。

完整修改代码

import random 
import pandas as pd

# 生成数据部分保持不变
years = [2000, 2001, 2003]
categories = ['CatA', 'CatB', 'CatC'] 
statuses = ['Active', 'Inactive']
data = []

for year in years:
        for _ in range(3):
            category = random.choice(categories)
            status = random.choice(statuses)
            data.append([year, category, status])

df = pd.DataFrame(data, columns=['Year', 'Category', 'Status'])

# 创建交叉表并添加列总计
cross_tab = pd.crosstab([df.Year, df.Status], df.Category)
category_totals = cross_tab.sum(axis=1) 
cross_tab = pd.concat([category_totals, cross_tab], axis=1) 
cross_tab.rename(columns={0: 'Total'}, inplace=True)

# 计算年份总计行,并转换为双层索引
year_totals = cross_tab.sum(level="Year")
# 为总计行构造(Year, 'Total')格式的双层索引
year_totals.index = pd.MultiIndex.from_tuples(
    [(year, 'Total') for year in year_totals.index],
    names=['Year', 'Status']
)

# 合并原交叉表和总计行
combined = pd.concat([cross_tab, year_totals])

# 重新排序索引,让每个年份的Total行排在最前面
combined = combined.sort_index(level=['Year', 'Status'], key=lambda x: x == 'Total', ascending=False)

# 可选:优化显示,同一Year下非Total行的Year值设为空
combined = combined.reset_index()
combined['Year'] = combined['Year'].where(combined['Status'] == 'Total', '')
combined = combined.set_index(['Year', 'Status'])

print(combined)

关键步骤说明

  1. 索引结构统一:用pd.MultiIndex.from_tuples将总计行的单层Year索引转换为(Year, 'Total')的双层索引,和原交叉表索引结构完全匹配。
  2. 合并与排序:合并后通过sort_index的key参数,让每个年份的'Total'行优先排在该年份的Active/Inactive行之前。
  3. 显示优化:通过重置索引再重新设置的方式,将同一Year下非Total行的Year值置空,完全匹配期望的表格显示效果。

内容的提问来源于stack exchange,提问作者as_meth

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 16:17:07