PySpark DataFrame数值列拆分为多行的实现方法咨询
PySpark宽表转长表实现方案
你需要实现的是典型的宽表转长表(Unpivot)操作,有以下两种可行实现思路:
方案1:使用stack函数实现Unpivot(性能最优,推荐)
直接使用PySpark内置的逆透视函数完成列转行,仅需扫描一次原表,性能远高于多次扫描的方案,示例代码如下:
from pyspark.sql import functions as F # 1. 先处理百分比列,添加%后缀 df_processed = df.withColumn("values_in_percent", F.concat(F.col("values_in_percent"), F.lit("%"))) # 2. 使用stack函数完成列转行,拆分出key_1和临时值列 df_unpivot = df_processed.select( "Region", "Location", "Month", "Services", "Type", F.expr("stack(2, 'values_in_millions', values_in_millions, 'values_in_percent', values_in_percent) as (key_1, temp_value)") ) # 3. 拆分出values_1和values_2列 df_result = df_unpivot.withColumn( "values_1", F.when(F.col("key_1") == "values_in_millions", F.col("temp_value")).otherwise(None) ).withColumn( "values_2", F.when(F.col("key_1") == "values_in_percent", F.col("temp_value")).otherwise(None) ).drop("temp_value")
方案2:使用unionAll拼接实现(逻辑直观,适合新手)
把两个值列分别处理成对应的子数据集,再合并为最终结果,逻辑简单易懂:
from pyspark.sql import functions as F # 处理values_in_millions对应的子数据集 df_million = df.select( "Region", "Location", "Month", "Services", "Type", F.lit("values_in_millions").alias("key_1"), F.col("values_in_millions").alias("values_1"), F.lit(None).alias("values_2") ) # 处理values_in_percent对应的子数据集 df_percent = df.select( "Region", "Location", "Month", "Services", "Type", F.lit("values_in_percent").alias("key_1"), F.lit(None).alias("values_1"), F.concat(F.col("values_in_percent"), F.lit("%")).alias("values_2") ) # 合并两个子数据集得到最终结果 df_result = df_million.unionAll(df_percent)
注意事项
- 如果你不需要把百分比存为带%的字符串,仅需保留数值类型,去掉
F.concat(F.col("values_in_percent"), F.lit("%"))这部分逻辑即可。 - 如果你后续需要扩展更多值列,优先选择stack方案,可避免重复扫描原表带来的性能损耗。
内容的提问来源于stack exchange,提问作者user175025
相关产品推荐
相关产品推荐

