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

如何将PySpark DataFrame行值转换为同内行其他值的关联关系

如何将Spark DataFrame的行值转换为该行内其他所有值的关联关系

我来帮你搞定这个需求——把DataFrame每行里的每个元素,和该行内其他所有元素建立关联关系。核心思路就是先把每行的所有值收集成一个列表,再通过Spark的函数生成元素间的配对。下面是具体的实现步骤和代码示例:

第一步:准备示例DataFrame

先创建你给出的输入DataFrame,方便后续测试:

from pyspark.sql import SparkSession

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

# 构建输入DataFrame
df = spark.createDataFrame(
    [('1111','1010', 'aaaa'), ('2222','2020', 'bbbb'), ('3333','3030', 'cccc')], 
    ['company_id', 'client_id', 'partner_id']
)

# 查看原始数据
df.show()

运行后你会看到:

+----------+---------+----------+
|company_id|client_id|partner_id|
+----------+---------+----------+
|      1111|     1010|      aaaa|
|      2222|     2020|      bbbb|
|      3333|     3030|      cccc|
+----------+---------+----------+

第二步:把每行字段转换成元素列表

我们先把每行的三个字段值合并成一个数组,这样后续就能统一处理所有元素了:

from pyspark.sql.functions import array, col

df_with_array = df.withColumn("all_elements", array(col("company_id"), col("client_id"), col("partner_id")))
df_with_array.show(truncate=False)

输出结果:

+----------+---------+----------+---------------------+
|company_id|client_id|partner_id|all_elements         |
+----------+---------+----------+---------------------+
|1111      |1010     |aaaa      |[1111, 1010, aaaa]   |
|2222      |2020     |bbbb      |[2222, 2020, bbbb]   |
|3333      |3030     |cccc      |[3333, 3030, cccc]   |
+----------+---------+----------+---------------------+

第三步:生成所有元素间的关联对

接下来要实现每个元素和其他元素的配对。这里我们可以用posexplode获取每个元素的位置和值,再通过关联过滤掉自身,得到所有关联关系:

# 先展开数组,得到每个元素的位置和值
exploded_df = df_with_array.select(
    col("company_id"),
    posexplode(col("all_elements")).alias("pos", "source_value")
)

# 关联原数组,过滤掉自身位置,生成目标值
result_df = exploded_df.join(
    df_with_array.select(col("company_id"), posexplode(col("all_elements")).alias("target_pos", "target_value")),
    (exploded_df.company_id == df_with_array.company_id) & (exploded_df.pos != df_with_array.target_pos),
    "inner"
).select(
    exploded_df.company_id,
    exploded_df.source_value,
    df_with_array.target_value
)

# 查看最终结果
result_df.show()

运行后会得到每行所有元素的双向关联对:

+----------+------------+------------+
|company_id|source_value|target_value|
+----------+------------+------------+
|      1111|        1111|        1010|
|      1111|        1111|        aaaa|
|      1111|        1010|        1111|
|      1111|        1010|        aaaa|
|      1111|        aaaa|        1111|
|      1111|        aaaa|        1010|
|      2222|        2222|        2020|
|      2222|        2222|        bbbb|
|      2222|        2020|        2222|
|      2222|        2020|        bbbb|
|      2222|        bbbb|        2222|
|      2222|        bbbb|        2020|
|      3333|        3333|        3030|
|      3333|        3333|        cccc|
|      3333|        3030|        3333|
|      3333|        3030|        cccc|
|      3333|        cccc|        3333|
|      3333|        cccc|        3030|
+----------+------------+------------+

可选:生成无重复的单向关联对

如果你只需要单向的关联(比如只保留1111->1010,不需要反向的1010->1111),只需要修改关联时的过滤条件,把!=改成<就行:

result_unique_df = exploded_df.join(
    df_with_array.select(col("company_id"), posexplode(col("all_elements")).alias("target_pos", "target_value")),
    (exploded_df.company_id == df_with_array.company_id) & (exploded_df.pos < df_with_array.target_pos),
    "inner"
).select(
    exploded_df.company_id,
    exploded_df.source_value,
    df_with_array.target_value
)

result_unique_df.show()

输出的就是去重后的单向关联:

+----------+------------+------------+
|company_id|source_value|target_value|
+----------+------------+------------+
|      1111|        1111|        1010|
|      1111|        1111|        aaaa|
|      1111|        1010|        aaaa|
|      2222|        2222|        2020|
|      2222|        2222|        bbbb|
|      2222|        2020|        bbbb|
|      3333|        3333|        3030|
|      3333|        3333|        cccc|
|      3333|        3030|        cccc|
+----------+------------+------------+

另一种简洁实现:用高阶函数

如果你喜欢更简洁的写法,可以用Spark的高阶函数transform和filter来实现,不用join:

from pyspark.sql.functions import expr, explode

df_result = df_with_array.select(
    col("company_id"),
    explode(
        expr("""
            transform(all_elements, (val, i) -> 
                filter(all_elements, (val2, j) -> i != j)
            )
        """)
    ).alias("target_values"),
    explode(col("all_elements")).alias("source_value")
).select(
    col("company_id"),
    col("source_value"),
    explode(col("target_values")).alias("target_value")
).distinct()

df_result.show()

这个方法和join的效果完全一致,只是写法更紧凑。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 03:32:36