如何使用PySpark对DataFrame执行逆透视(Unpivot)转换?
PySpark宽表转长表(逆透视)正确实现
要实现宽格式DataFrame转长格式,PySpark里直接用stack函数就能搞定,不用绕弯路。以下是具体步骤和代码:
核心思路
逆透视的本质是把多列(指标列)“堆叠”成两列:一列存原列名(指标名称),一列存对应的值。stack函数就是干这个的,它需要指定要堆叠的列数,然后依次列出'列名', 列的配对。
代码实现
假设你的宽表df结构如下(以销售数据为例):
| Ano | Vendas | Custos | Lucro |
|---|---|---|---|
| 2020 | 1000 | 500 | 500 |
| 2021 | 1200 | 600 | 600 |
方法1:动态适配列(推荐)
如果指标列数量不固定,用动态生成stack表达式的方式,避免硬编码:
from pyspark.sql.functions import expr # 排除年份列"Ano",得到所有要逆透视的指标列 unpivot_columns = [col for col in df.columns if col != "Ano"] # 构造stack表达式:stack(列数, '列名1', 列1, '列名2', 列2, ...) stack_expression = f"stack({len(unpivot_columns)}, {', '.join([f'\'{col}\', {col}' for col in unpivot_columns])}) as (Metrica, Valor)" # 执行逆透视,保留年份列,加上堆叠后的两列 long_format_df = df.select("Ano", expr(stack_expression))
方法2:硬编码列(适合列固定的场景)
如果指标列是固定的,直接写死stack参数更直观:
from pyspark.sql.functions import expr long_format_df = df.select( "Ano", expr("stack(3, 'Vendas', Vendas, 'Custos', Custos, 'Lucro', Lucro) as (Metrica, Valor)") )
结果验证
运行后得到的长表就是你要的格式:
| Ano | Metrica | Valor |
|---|---|---|
| 2020 | Vendas | 1000 |
| 2020 | Custos | 500 |
| 2020 | Lucro | 500 |
| 2021 | Vendas | 1200 |
| 2021 | Custos | 600 |
| 2021 | Lucro | 600 |
常见问题排查
如果你的代码输出不对,大概率是这几个原因:
stack函数第一个参数(要堆叠的列数)和实际列数不匹配,比如你有3个指标列,却写了2;- 列名配对写错,比如把
'Vendas', Vendas写成了Vendas, 'Vendas',顺序反了; - 没有保留
Ano列,导致年份信息丢失。
内容的提问来源于stack exchange,提问作者Rui
相关产品推荐
相关产品推荐

