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

无需SQL表达式,基于ID从数组取值添加DataFrame列

问题描述

我有一个DataFrame df,数据结构如下:

{
    "data":[
        {
            "id":"a",
            "val":1
        },
        {
            "id":"b",
            "val":2
        }
    ]
}

需要添加新列test,使其值为数组中id等于'b'的项的val(即2)。目前通过SQL表达式实现了需求:

import pyspark.sql.functions as F

(
    df
    .withColumn(
        "test",
        F.expr("filter(data,x->x.id=='b')")[0]["val"]
    )
    .show()
)

执行结果符合预期:

+----------------+----+
| data           |test|
+----------------+----+
|[{a, 1}, {b, 2}]| 2  |
+----------------+----+

想知道有没有不依赖SQL、更“原生”的PySpark实现方式?


解决方案

方法1:使用array_filter(PySpark 3.1+推荐)

PySpark 3.1及以上版本提供了原生的array_filter函数,无需编写SQL表达式就能完成数组过滤:

import pyspark.sql.functions as F

(
    df
    .withColumn(
        "filtered_data",
        F.array_filter(F.col("data"), lambda x: x["id"] == "b")
    )
    .withColumn("test", F.col("filtered_data")[0]["val"])
    .drop("filtered_data")  # 可选:清理中间临时列
    .show()
)

array_filter接收数组列和过滤逻辑的lambda表达式,直接筛选出id为'b'的元素,之后取第一个元素的val字段即可。

方法2:兼容低版本的transform+aggregate组合

如果你的PySpark版本低于3.1,可以用transform标记目标元素,再通过aggregate提取对应值:

import pyspark.sql.functions as F

(
    df
    .withColumn(
        "test",
        F.aggregate(
            F.transform(F.col("data"), lambda x: F.when(x["id"] == "b", x["val"]).otherwise(None)),
            F.lit(None),
            lambda acc, x: F.coalesce(x, acc)
        )
    )
    .show()
)

transform会将符合条件的元素替换为对应的val值,不符合的设为None;aggregate则通过coalesce提取第一个非空值(即目标的2)。

方法3:固定索引直接取值(仅适用于元素顺序固定场景)

如果能确保id为'b'的元素在数组中的位置固定(比如总是第2个元素),可以直接通过索引取值:

import pyspark.sql.functions as F

(
    df
    .withColumn("test", F.col("data")[1]["val"])
    .show()
)

注意:这种方法依赖数组元素的顺序,一旦数据顺序变化会导致结果错误,不推荐用于动态数据场景。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 21:50:05