PySpark/Pandas实现宽表转长表:操作名称及方法问询
宽表转长表(Unpivot)的操作名称与实现
你要做的这个操作叫做 Unpivot(逆透视/宽表转长表),核心是将原本按列分组的类别数据(比如月份)转为行维度,把多列合并为「类别标识列」和「对应值列」。
PySpark 实现(优先推荐)
假设输入的宽表结构如下:
| year | Jan | Feb | Mar |
|---|---|---|---|
| 2023 | 100 | 150 | 200 |
| 2024 | 120 | 180 | 220 |
方法1:使用 melt 函数(Spark 3.1+ 适用)
Spark 3.1 及以上版本内置了melt函数,能快速完成逆透视:
from pyspark.sql import functions as F from pyspark.sql.types import StringType # 假设df是你的输入DataFrame melted_df = df.melt( id_vars=["year"], # 保留的主键列 value_vars=["Jan", "Feb", "Mar"], # 需要转换的月份列 var_name="month", # 生成的月份标识列 value_name="gain" # 生成的数值列 ) # 转换为「年份_两位月份」格式 month_code_map = {"Jan": "01", "Feb": "02", "Mar": "03"} get_month_code = F.udf(lambda m: month_code_map[m], StringType()) final_df = melted_df.withColumn( "year_month", F.concat(F.col("year").cast(StringType()), F.lit("_"), get_month_code(F.col("month"))) ).drop("year", "month") final_df.show()
方法2:使用 stack 表达式(兼容低版本Spark)
如果你的Spark版本低于3.1,用SQL的stack表达式手动实现:
# 构造stack表达式:stack(列数, '列名1', 列值1, '列名2', 列值2, ...) stack_expr = "stack(3, 'Jan', Jan, 'Feb', Feb, 'Mar', Mar) as (month, gain)" melted_df = df.selectExpr("year", stack_expr) # 生成year_month列 final_df = melted_df.withColumn( "year_month", F.concat( F.col("year").cast(StringType()), F.lit("_"), F.when(F.col("month") == "Jan", "01") .when(F.col("month") == "Feb", "02") .when(F.col("month") == "Mar", "03") ) ).drop("year", "month") final_df.show()
Pandas 实现
先构造示例输入数据:
import pandas as pd df = pd.DataFrame({ "year": [2023, 2024], "Jan": [100, 120], "Feb": [150, 180], "Mar": [200, 220] })
使用 melt 函数
Pandas的melt是处理这类转换的标准工具:
# 第一步:逆透视宽表 melted_df = df.melt( id_vars=["year"], value_vars=["Jan", "Feb", "Mar"], var_name="month", value_name="gain" ) # 第二步:生成year_month列 month_code_map = {"Jan": "01", "Feb": "02", "Mar": "03"} melted_df["year_month"] = melted_df["year"].astype(str) + "_" + melted_df["month"].map(month_code_map) # 清理冗余列 final_df = melted_df.drop(["year", "month"], axis=1) print(final_df)
内容的提问来源于stack exchange,提问作者vinicius de novaes
相关产品推荐
相关产品推荐

