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

如何按优先级从多列取值聚合PySpark DataFrame的ID分组?

PySpark实现按优先级合并ID并选取有效值

需求说明

现有PySpark DataFrame,每个ID对应多行数据,每行仅一个Type1-Type5列包含有效值;需要将每个ID合并为一行,生成Type列,取值规则为按Type1>Type2>Type3>Type4>Type5的优先级,选取第一个非空且大于0的值。

实现方案

以下提供两种可行的实现方式,可根据实际场景选择:


方法一:聚合后按优先级筛选(直观简洁)

先对每个ID聚合各Type列的最大值(因每个ID在单个Type列最多一个有效值),再通过coalesce结合when条件按优先级选取符合要求的值:

from pyspark.sql import SparkSession
from pyspark.sql import functions as F

# 初始化SparkSession
spark = SparkSession.builder.appName("MergeTypePriority").getOrCreate()

# 构造示例DataFrame
data = [
    ("001", None, 100, None, None, None),
    ("001", None, None, None, None, 200),
    ("001", None, None, 300, None, None),
    ("001", None, None, None, 150, None),
    ("002", 0, None, None, None, None),
    ("002", None, None, 300, None, None),
    ("002", None, 200, None, None, None),
    ("002", None, None, None, None, 400)
]
schema = ["ID", "Type1", "Type2", "Type3", "Type4", "Type5"]
df = spark.createDataFrame(data, schema=schema)

# 1. 聚合每个ID的各Type列最大值
agg_df = df.groupBy("ID").agg(
    F.max("Type1").alias("Type1"),
    F.max("Type2").alias("Type2"),
    F.max("Type3").alias("Type3"),
    F.max("Type4").alias("Type4"),
    F.max("Type5").alias("Type5")
)

# 2. 按优先级选取第一个非空且>0的值
result_df = agg_df.select(
    "ID",
    F.coalesce(
        F.when(F.col("Type1") > 0, F.col("Type1")),
        F.when(F.col("Type2") > 0, F.col("Type2")),
        F.when(F.col("Type3") > 0, F.col("Type3")),
        F.when(F.col("Type4") > 0, F.col("Type4")),
        F.when(F.col("Type5") > 0, F.col("Type5"))
    ).alias("Type")
)

# 查看结果
result_df.show()

方法二:长格式转换+排序取首(扩展性强)

将宽表转换为长表,提取有效数据并标记优先级,再按ID分组后按优先级排序取第一个有效值,适合Type列数量较多的场景:

from pyspark.sql import SparkSession
from pyspark.sql import functions as F
from pyspark.sql.window import Window

# 初始化SparkSession
spark = SparkSession.builder.appName("MergeTypePriority").getOrCreate()

# 构造示例DataFrame(同方法一)
data = [
    ("001", None, 100, None, None, None),
    ("001", None, None, None, None, 200),
    ("001", None, None, 300, None, None),
    ("001", None, None, None, 150, None),
    ("002", 0, None, None, None, None),
    ("002", None, None, 300, None, None),
    ("002", None, 200, None, None, None),
    ("002", None, None, None, None, 400)
]
schema = ["ID", "Type1", "Type2", "Type3", "Type4", "Type5"]
df = spark.createDataFrame(data, schema=schema)

# 定义Type列优先级(数字越小优先级越高)
type_priority = {"Type1": 1, "Type2": 2, "Type3": 3, "Type4": 4, "Type5": 5}

# 1. 转换为长表,过滤空值和<=0的无效数据,添加优先级列
long_df = df.select(
    "ID",
    F.explode(
        F.array(
            *[F.struct(F.lit(col).alias("type_name"), F.col(col).alias("value")) for col in schema[1:]]
        )
    ).alias("type_info")
).select(
    "ID", "type_info.type_name", "type_info.value"
).filter(
    (F.col("value").isNotNull()) & (F.col("value") > 0)
).withColumn(
    "priority", F.lit(type_priority).getItem(F.col("type_name"))
)

# 2. 按ID分组,按优先级升序排序后取第一个值
window_spec = Window.partitionBy("ID").orderBy("priority")
result_df = long_df.withColumn(
    "Type", F.first("value", ignorenulls=True).over(window_spec)
).select("ID", "Type").distinct()

# 查看结果
result_df.show()

结果输出

两种方法最终都会得到目标DataFrame:

+---+----+
| ID|Type|
+---+----+
|001| 100|
|002| 200|
+---+----+

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 01:17:23