Pandas:stack() 和 unstack()

type
status
date
slug
summary
tags
category
icon
password
网址
作者
标签
文章链接
发布时间
来源

stack()unstack()

当你在处理包含某种序列(例如时间序列数据)的变量的数据集时,数据通常需要进行重塑. Pandas 提供了各种用于重塑 DataFrame 的内置方法。其中,stack()unstack() 是最流行的 2 种重组列和行的方法:
  • stack():从列到行堆叠
  • unstack():从行到列取消堆叠
stack() unstack() 似乎使用起来相当简单,但你仍然应该知道一些技巧来加快数据分析。
在本文中,我将分享 Pandas 的几个技巧:
  • 单层
  • 多层次:简单案例
  • 多层次:缺失值
  • 多个级别:指定要堆叠的级别
  • 多个级别:删除缺失值
  • unstack: 简单案例
  • unstack:更多用法

单层

最简单的 stack()可以应用于具有单层列的 DataFrame。它只是将标签从列堆叠到行并输出一个系列。
notion image

多层次:简单案例

通常,我们会在具有多级列的 DataFrame 上使用 stack()
让我们创建一个 DataFrame。有多种方法可以创建具有多级列的 DataFrame,最简单的方法之一是创建 MultiIndex 对象 MultiIndex.from_tuples() 并将结果传递给 pd.DataFrame() 中的 columns 参数:
notion image
通过调用 stack(),它将获取列级别(mph, m/s) 并将其堆叠到行轴上。
notion image
注意:在幕后,它根据参数 level 运行操作。 参数 level 默认为 -1 ,它采用最内层并将其从列轴堆叠到行轴上。

多层次:缺失值

在堆叠具有多级列的 DataFrame 时,通常会出现缺失值。让我们创建另一个 DataFrame 示例:
与前面的示例 multi_col_1 在第一级中具有相同的值“Wind”不同,multi_col_2 具有 2 个不同的值“Wind”和“Temperature”。 现在,我们得到了缺失值,因为堆叠的 DataFrame 比原始 DataFrame 有更多的值,并且缺失值用 NaN 填充。
notion image

多层次:规定要堆叠的层次

stack() 中的第一个参数是 level,它控制堆叠的级别。 让我们创建一个具有 2 个不同级别的 MultiIndex:
我们可以传递一个数字来规定要堆叠的级别。 要规定要堆叠的多个级别,我们可以传递一个列表:
notion image

多层次:删除缺失值

默认情况下,调用 stack() 时会删除所有值缺失的行,可以通过将 dropna 设置为 False 来控制此行为:
notion image

unstack: 简单案例

同样,Pandas unstack() 也支持参数级别,默认为 -1,它将对最内层索引应用操作
通过在具有 MultiIndex 的 Series 上调用 unstack(),它会将最内层的索引取消堆叠到列上。 要指定要取消堆叠的级别,我们可以传递级别编号:
notion image

unstack:更多用法

通常,我们会在更多级别上使用 unstack()
让我们看一个具有 3 个级别的示例:
通过调用 unstack(),它将最里面的索引解栈到列中。 例如,我们可以使用方法链来运行另一个 unstack() 或传递一个列表
notion image
notion image
notion image
notion image

groupby().count().unstack()

groupby().count().unstack() 是 Pandas 数据分析中一个非常经典且高效的“三步组合拳”,用于将原始数据快速转化为二维交叉表(Contingency Table)或透视表(Pivot Table),以便于进行分类统计和可视化。
这个组合拳的核心在于将数据的两个分类维度分别放置在表的行和列上,单元格中则是它们的计数结果。

场景示例:

假设你有一张销售记录表,包含 Region(地区)和 Product(产品)。你想知道每个地区购买每种产品的次数
Region
Product
Number
East
A
1
West
B
1
East
A
1
South
C
1
West
A
1
East
B
1
South
A
1
West
B
1
East
C
1
目标结果:
Region \ Product
A
B
C
East
2
1
1
South
1
NaN
1
West
1
2
NaN

三步拆解

我们将使用模拟数据来详细演示每一步的变化。

初始数据 (DataFrame)

步骤 1: groupby(['Dim1', 'Dim2'])

  • 代码: df.groupby(['Region', 'Product'])
  • 作用: 按照指定的两个维度(本例中是 RegionProduct)的所有可能组合对数据进行分组。
  • 结果: 创建一个 DataFrameGroupBy 对象,这是一个中间状态,尚未进行计算。

步骤 2: .count()

  • 代码: df.groupby(['Region', 'Product'])['Number'].count()
  • 作用: 对上一步分组的结果进行聚合计算。我们选择了任意一个非分组列(这里是 'Number')来执行 count() 计数操作。
    • 注意: .count() 统计的是每组中非空值的数量。如果是用 .size(),则统计的是每组的记录总数(包含 NaN)。
  • 结果: 得到一个 Series 对象,它的索引是两级分层索引(MultiIndex)

步骤 3: .unstack()

  • 代码: df.groupby(['Region', 'Product'])['Number'].count().unstack()
  • 作用: 将步骤 2 得到的 MultiIndex Series 进行重塑(列转行)。
    • 默认行为: unstack() 默认会选取最内层(最右边)的索引(即 'Product')并将其转换为新的列标题
    • 未被转换的索引(即 'Region')则保留为新的行索引。
  • 结果: 得到一个清晰的 DataFrame 交叉表
关键细节:
  1. 如果某个组合在原始数据中不存在(例如:假设 North 地区没有买过 Lemon),unstack() 会自动用 NaN(Not a Number)填充该单元格。
  1. 我们可以紧接着使用 .fillna(0)NaN 替换为 0。

高级用法:指定 level

unstack() 中,你可以指定 level 参数来选择要提升到列的索引级别。
  • unstack(level=1):等同于默认行为,提升第二级索引(Product)。
  • unstack(level=0):提升第一级索引(Region)到列标题。

groupby().size().unstack()

.size()专门用于计算分组中的行数(即记录数),它返回一个 Series,而不是 DataFrame,但对于计数而言更加直接

参考资料

一文详解:7个 Pandas stack() 和 unstack() 使用技巧 - [Link] -
 
Prev
pd.cut()
Next
行为代理理论
Loading...
Article List
Practice makes perfect
文献集锦
如何理论创新?
管理学理论集锦
Python实际应用
聚类标准误与固定效应
巫师3:狂猎
Stata应用技巧
Python知识与技巧
双重差分法(DID)
创新文献阅读与摘要
计量经济学
Python绘图相关