如何删除PySpark DataFrame中重复Name且Code为Null的记录?
解决PySpark DataFrame按Name去重并保留有效Code行的问题
没问题,这个需求用PySpark的窗口函数就能完美解决,我来一步步给你演示怎么做:
首先先确认下你的原始数据和DataFrame结构,你给出的代码是这样的:
# Prepare Data data = [('Italy', 'ITA'), \ ('China', 'CHN'), \ ('China', None), \ ('France', 'FRA'), \ ('Spain', None), \ ('Taiwan', 'TWN'), \ ('Taiwan', None) ] # Create DataFrame columns = ['Name', 'Code'] df = spark.createDataFrame(data = data, schema = columns) df.show(truncate=False)
运行后会得到原始的DataFrame,里面存在Name重复且对应Code为Null的行。
实现思路
我们的目标是:
- 对于Name重复出现的分组,只保留其中Code不为Null的那一行
- 对于Name只出现一次的行,不管Code是否为Null都保留
- 最终每个Name只留一条记录
核心是用窗口函数给每个Name分组的行做排序标记,优先保留Code非Null的行,然后只取每个分组的第一行。
完整代码实现
from pyspark.sql.window import Window import pyspark.sql.functions as F # 定义窗口:按Name分组,排序规则是Code非Null的行优先排在前面 window_spec = Window.partitionBy("Name").orderBy( F.when(F.col("Code").isNotNull(), 0).otherwise(1) ) # 添加行号列,每个Name分组内按排序规则生成行号 df_with_row_num = df.withColumn("row_num", F.row_number().over(window_spec)) # 过滤出每个分组的第一行,就是我们需要保留的记录 result_df = df_with_row_num.filter(F.col("row_num") == 1).drop("row_num") # 查看结果 result_df.show(truncate=False)
结果说明
运行上面的代码后,你会得到期望的输出:
| Name | Code |
|---|---|
| Italy | ITA |
| China | CHN |
| France | FRA |
| Spain | null |
| Taiwan | TWN |
这里的逻辑是:
- 窗口函数按
Name分组,排序时用when表达式给Code非Null的行标记为0,Null的标记为1,这样非Null的行就会排在分组的最前面 row_number()会给每个分组内的行按排序顺序生成1、2、3...的行号- 过滤
row_num=1的行,就保证了每个Name只留一行——如果有非Null的Code就留那行,没有的话就留唯一的那行(比如Spain)
内容的提问来源于stack exchange,提问作者Mohammad
相关产品推荐
相关产品推荐

