在工作中我们经常面对各种缺失值的处理,当使用pandas,缺失值可以使用fillna,指定method=ffill或bfill就能实现
缺失值的前向或后向填充。但是在spark应用中,需要稍微做一些改变。比如说我们先创建一个DataFrame:
df = spark.createDataFrame(
[("a", 1, '2019-06-15 13:20'),
("a",2, None),("a",3, None),
("a",4, '2019-06-15 13:40'),
("a",5, '2019-06-15 14:40'),
("a",6, None),
("b",1, '2019-06-15 13:42'),
("b",2, None),
("b",3, None)],
["id","num", "time"]
)
df.show()
+---+---+----------------+
| id|num| time|
+---+---+----------------+
| a| 1|2019-06-15 13:20|
| a| 2| null|
| a| 3| null|
| a| 4|2019-06-15 13:40|
| a| 5|2019-06-15 14:40|
| a| 6| null|
| b| 1|2019-06-15 13:42|
| b| 2| null|
| b| 3| null|
+---+---+----------------+
假如有这样的场景:对于不同的用户"a"和"b",它有一个维度num,还有一个时间列。但是time列存在很多缺失值,现在想要填充这些null值,要求是向前填,
也就是说如果当前有值不作处理,若为空值,就向前找离他最近的值填充。
要实现这个功能就要借助spark的windows函数,代码如下:
from pyspark.sql import Window
from pyspark.sql.functions import last
import sys
# 开窗函数,以id做分组,指定排序方式,设置窗口大小
window = Window.partitionBy("id").orderBy("num").rowsBetween(-sys.maxsize, 0)
# last函数,返回分组中的最后一个值。ignorenulls为True表示只对null值应用
filled = last(df["time"], ignorenulls=True).over(window)
spark_df = df.withColumn("tmp_time", filled)
spark_df.orderBy("id", "num").show().show()
结果如下:
+---+---+----------------+----------------+
| id|num| time| tmp_time|
+---+---+----------------+----------------+
| a| 1|2019-06-15 13:20|2019-06-15 13:20|
| a| 2| null|2019-06-15 13:20|
| a| 3| null|2019-06-15 13:20|
| a| 4|2019-06-15 13:40|2019-06-15 13:40|
| a| 5|2019-06-15 14:40|2019-06-15 14:40|
| a| 6| null|2019-06-15 14:40|
| b| 1|2019-06-15 13:42|2019-06-15 13:42|
| b| 2| null|2019-06-15 13:42|
| b| 3| null|2019-06-15 13:42|
+---+---+----------------+----------------+
可以发现确实实现了这个功能。
原文参考这个博客,有兴趣可以了解下
https://johnpaton.net/posts/forward-fill-spark/