pyspark向前填充具有特定值的时间戳列(1秒)

时间:2019-07-09 07:54:53

标签: python pandas pyspark

过去我曾问过有关python pandas库的问题:pandas forward fill Time Stamp columns with specific value (1 second)

但是现在我将在pyspark中进行大量数据处理,因此会在pyspark中寻求另一种解决方案:

我有一个Spark DataFrame:

df = spark.createDataFrame([Row(a=1, b='2018-09-26 04:38:32.544', c='11', d='foo'),
                            Row(a=2, b='', c='22', d='bar'),
                            Row(a=3, b='', c='33', d='foo'),
                            Row(a=4, b='', c='44', d='bar'),
                            Row(a=5, b='2018-09-26 04:58:32.544', c='55', d='foo'),
                            Row(a=6, b='', c='66', d='bar')])
df.show(truncate=False)

|a  |b                      |c  |d  |
+---+-----------------------+---+---+
|1  |2018-09-26 04:38:32.544|11 |foo|
|2  |                       |22 |bar|
|3  |                       |33 |foo|
|4  |                       |44 |bar|
|5  |2018-09-26 04:58:32.544|55 |foo|
|6  |                       |66 |bar|
+---+-----------------------+---+---+

我想从以前的可用版本中连续向每个NaT添加1秒:

|a  |b                      |c  |d  |
+---+-----------------------+---+---+
|1  |2018-09-26 04:38:32.544|11 |foo|
|2  |2018-09-26 04:39:32.544|22 |bar|
|3  |2018-09-26 04:40:32.544|33 |foo|
|4  |2018-09-26 04:41:32.544|44 |bar|
|5  |2018-09-26 04:58:32.544|55 |foo|
|6  |2018-09-26 04:59:32.544|66 |bar|
+---+-----------------------+---+---+

我读到应该避免使用 udf ,因为它们会减慢数百万行的处理速度。感谢您的帮助!

1 个答案:

答案 0 :(得分:1)

这可能不是最有效的解决方案,因为我们无法根据您的要求对数据帧进行分区。这意味着所有数据都被加载到单个分区并在那里排序。也许有人可以提出更好的解决方案。

下面的代码使用lag窗口函数,该函数返回上一行的值。我们仅在b的当前值为null时应用此方法,否则我们将保留当前值。当当前值为空时,我们将上一行的值增加一秒钟。我们必须这样做几次,因为在b列中包含null的行,并且在'b'列中也包含null的前一行将从lag返回空值(即lag不能连续应用,因此我们必须自己做)。

import pyspark.sql.functions as F
from pyspark.sql import Row
from pyspark.sql import Window

df = spark.createDataFrame([Row(a=1, b='2018-09-26 04:38:32.544', c='11', d='foo'),
                            Row(a=2, b='', c='22', d='bar'),
                            Row(a=3, b='', c='33', d='foo'),
                            Row(a=4, b='', c='44', d='bar'),
                            Row(a=5, b='2018-09-26 04:58:32.544', c='55', d='foo'),
                            Row(a=6, b='', c='66', d='bar')])

df = df.withColumn('a',  df.a.cast("int"))
df = df.withColumn('b',  df.b.cast("timestamp"))

w = Window.orderBy('a')

while df.filter(df.b.isNull()).count() != 0:
    df = df.withColumn('b', F.when(df.b.isNotNull(), df.b).otherwise(F.lag('b').over(w)  + F.expr('INTERVAL 1 SECONDS')))

df.show(truncate=False)

输出:

+---+-----------------------+---+---+ 
| a |                     b | c | d | 
+---+-----------------------+---+---+ 
| 1 |2018-09-26 04:38:32.544|11 |foo| 
| 2 |2018-09-26 04:38:33.544|22 |bar| 
| 3 |2018-09-26 04:38:34.544|33 |foo| 
| 4 |2018-09-26 04:38:35.544|44 |bar| 
| 5 |2018-09-26 04:58:32.544|55 |foo| 
| 6 |2018-09-26 04:58:33.544|66 |bar| 
+---+-----------------------+---+---+