PySpark DataFrame基于条件前向填充问题:filled与filled1结果相同原因
PySpark 仅在flag=1时实现前向填充的问题解析与解决方法
问题原因
你当前的代码逻辑没有实现「仅当flag=1时触发前向填充,后续flag=0的行沿用最近的flag=1对应的salary」的需求,导致filled和filled1结果一致,核心问题点:
- 原代码中
when(col("flag") == 1, last(col("salary"), True).over(window))里的last(salary),在当前窗口(从分区开头到当前行)中,当flag=1时,当前行的salary就是窗口内最后一个非空值,返回结果和当前行的salary完全相同;而otherwise(col("salary"))直接取原salary。所以无论flag是0还是1,filled列最终都是原salary,和直接取全局last的filled1自然没有区别。 - 你的真实需求是把flag=1的salary作为「填充锚点」,后续flag=0的行需要继承最近的这个锚点值,但原代码没有对锚点值进行跨行传递的逻辑。
解决方法
要实现需求,需要先标记出flag=1的锚点salary,再对锚点值做前向填充,最后合并原salary和填充值:
from pyspark.sql import SparkSession from pyspark.sql.functions import col, when, last from pyspark.sql.window import Window spark = SparkSession.builder.getOrCreate() data = [("person1", "1", 100, 0), ("person1", "2", 1000, 1), ("person1", "3", 1000, 0), ("person2", "1", 5, 0), ("person2", "2", 5, 0), ("person2", "3", 3, 0), ("person2", "4", 10, 1), ("person2", "5", 10, 0)] df = spark.createDataFrame(data, ["person", "date", "salary", "flag"]) # 定义窗口:按person分区,按date排序,窗口范围从开头到当前行 window = Window.partitionBy("person").orderBy("date").rowsBetween(Window.unboundedPreceding, Window.currentRow) # 创建临时列:仅flag=1时保留salary,其余为null df = df.withColumn("flagged_salary", when(col("flag") == 1, col("salary"))) # 对flagged_salary做前向填充,取最近的非null值(即最近的flag=1的salary) df = df.withColumn("filled", last(col("flagged_salary"), ignorenulls=True).over(window)) # 最终填充逻辑:如果filled有值(即存在之前的flag=1锚点)则用filled,否则用原salary df = df.withColumn("final_filled", when(col("filled").isNotNull(), col("filled")).otherwise(col("salary"))) df.select("person", "date", "salary", "flag", "final_filled").show()
输出结果
+-------+----+------+----+-----------+ | person|date|salary|flag|final_filled| +-------+----+------+----+-----------+ |person1| 1| 100| 0| 100| |person1| 2| 1000| 1| 1000| |person1| 3| 1000| 0| 1000| |person2| 1| 5| 0| 5| |person2| 2| 5| 0| 5| |person2| 3| 3| 0| 3| |person2| 4| 10| 1| 10| |person2| 5| 10| 0| 10| +-------+----+------+----+-----------+
如果你的需求是「flag=0时,如果之前有flag=1的记录就填充,否则保持原salary;flag=1时保持原salary」,上述代码完全符合。如果需要调整逻辑(比如flag=0且无锚点时设为null),可以修改最后一步的when条件。
内容的提问来源于stack exchange,提问作者Henri
相关产品推荐
相关产品推荐

