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

PySpark数据清洗:识别重复列并生成指定结果列

问题描述

现有如下PySpark DataFrame:

+----+-------------+--------------+-------------+--------------+-------------+--------------+-------------+--------------+-------------+--------------+-------------+--------------+-------------+--------------+
| ID | Column_ID_1 | Column_txt_1 | Column_ID_2 | Column_txt_2 | Column_ID_3 | Column_txt_3 | Column_ID_4 | Column_txt_4 | Column_ID_5 | Column_txt_5 | Column_ID_6 | Column_txt_6 | Column_ID_7 | Column_txt_7 |
+----+-------------+--------------+-------------+--------------+-------------+--------------+-------------+--------------+-------------+--------------+-------------+--------------+-------------+--------------+
|  1 |         100 | abc          |       10025 | lkegls       |       64651 | wlejgnlwnr   |       65132 | wejgnn       |       65132 | wejgnn       |       65132 | wejgnn       |       65132 | wejgnn       |
|  2 |        1001 | def          |      648613 | esglknsl     |     3213213 | weklgnlkwn   |       51741 | oiqjerml     |  6565468165 | welkmlwe     |  6565468165 | welkmlwe     |  6565468165 | welkmlwe     |
|  3 |        1002 | hijlkefn     |        5654 | lengl        |      513220 | wlegnlw      |      513220 | wlegnlw      |      513220 | wlegnlw      |      513220 | wlegnlw      |      513220 | wlegnlw      |
+----+-------------+--------------+-------------+--------------+-------------+--------------+-------------+--------------+-------------+--------------+-------------+--------------+-------------+--------------+

需要识别每个ID对应的首次出现重复的Column_ID列名及其对应的Column_txt值,生成如下结果:

+----+------------------+----------------------+
| ID | Repeating_Column | Repeating Column_txt |
+----+------------------+----------------------+
|  1 | Column_ID_4      | wejgnn               |
|  2 | Column_ID_5      | welkmlwe             |
|  3 | Column_ID_3      | wlegnlw              |
+----+------------------+----------------------+
解决方案

步骤1:构建测试DataFrame

先还原示例中的测试数据:

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

spark = SparkSession.builder.appName("FindFirstRepeat").getOrCreate()

data = [
    (1, 100, "abc", 10025, "lkegls", 64651, "wlejgnlwnr", 65132, "wejgnn", 65132, "wejgnn", 65132, "wejgnn", 65132, "wejgnn"),
    (2, 1001, "def", 648613, "esglknsl", 3213213, "weklgnlkwn", 51741, "oiqjerml", 6565468165, "welkmlwe", 6565468165, "welkmlwe", 6565468165, "welkmlwe"),
    (3, 1002, "hijlkefn", 5654, "lengl", 513220, "wlegnlw", 513220, "wlegnlw", 513220, "wlegnlw", 513220, "wlegnlw", 513220, "wlegnlw")
]

columns = [
    "ID", "Column_ID_1", "Column_txt_1", "Column_ID_2", "Column_txt_2",
    "Column_ID_3", "Column_txt_3", "Column_ID_4", "Column_txt_4",
    "Column_ID_5", "Column_txt_5", "Column_ID_6", "Column_txt_6",
    "Column_ID_7", "Column_txt_7"
]

df = spark.createDataFrame(data, columns)

步骤2:UDF实现查找首次重复项

核心思路是将每对Column_ID_n和Column_txt_n打包成结构体数组,遍历数组找出第一个与已出现过的键重复的项:

# 生成包含(ID值、txt值、列名)的结构体数组
pair_cols = [
    F.struct(
        F.col(f"Column_ID_{i}").alias("id_val"),
        F.col(f"Column_txt_{i}").alias("txt_val"),
        F.lit(f"Column_ID_{i}").alias("col_name")
    ) for i in range(1, 8)
]
df_with_pairs = df.withColumn("pairs", F.array(*pair_cols))

# 定义UDF找出第一个重复项
def find_first_repeat(pairs):
    seen_keys = set()
    for pair in pairs:
        current_key = (pair.id_val, pair.txt_val)
        if current_key in seen_keys:
            return (pair.col_name, pair.txt_val)
        seen_keys.add(current_key)
    return (None, None)

find_first_repeat_udf = F.udf(find_first_repeat, "struct<Repeating_Column:string, `Repeating Column_txt`:string>")

# 应用UDF并提取结果
result_df = df_with_pairs.withColumn("repeat_info", find_first_repeat_udf(F.col("pairs"))) \
    .select("ID", "repeat_info.*")

# 展示结果
result_df.show()

步骤3:纯PySpark函数实现(无UDF)

如果偏好不用UDF,可通过数组展开+窗口函数实现:

# 生成带索引的(ID值、txt值、列名)结构体数组
pair_cols_with_idx = [
    F.struct(
        F.lit(i).alias("idx"),
        F.col(f"Column_ID_{i}").alias("id_val"),
        F.col(f"Column_txt_{i}").alias("txt_val"),
        F.lit(f"Column_ID_{i}").alias("col_name")
    ) for i in range(1, 8)
]
df_with_pairs = df.withColumn("pairs", F.array(*pair_cols_with_idx))

# 展开数组并标记重复项
df_exploded = df_with_pairs.select("ID", F.explode("pairs").alias("pair")) \
    .withColumn("count", F.count("*").over(F.window.partitionBy("ID", "pair.id_val", "pair.txt_val"))) \
    .filter(F.col("count") > 1)

# 找出每个ID最小重复索引对应的项
result_df = df_exploded.groupBy("ID") \
    .agg(F.min("pair.idx").alias("min_idx")) \
    .join(df_exploded, on=["ID", "min_idx"], how="left") \
    .select("ID", "pair.col_name", "pair.txt_val") \
    .withColumnRenamed("col_name", "Repeating_Column") \
    .withColumnRenamed("txt_val", "Repeating Column_txt")

result_df.show()

验证结果

两种方法执行后,输出均符合需求:

+---+------------------+----------------------+
| ID|Repeating_Column  |Repeating Column_txt   |
+---+------------------+----------------------+
|  1|Column_ID_4       |wejgnn                |
|  2|Column_ID_5       |welkmlwe              |
|  3|Column_ID_3       |wlegnlw               |
+---+------------------+----------------------+

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 06:37:02