Dataframe 特征工程继续上一个最后值发生

Dataframe 特征工程继续上一个最后值发生,dataframe,apache-spark,pyspark,apache-spark-sql,pyspark-sql,Dataframe,Apache Spark,Pyspark,Apache Spark Sql,Pyspark Sql,对于给定的数据帧 spark.createDataFrame([ ("2019-06-24T07:29:22.000+0000", "Image Quality: 75"), ("2019-06-25T07:29:22.000+0000", "Start scan"), ("2019-06-26T07:29:22.000+0000", "Image Quality: 95"), ("2019-06-27T07:29:22.000+0000", "Start scan"), (

对于给定的数据帧

spark.createDataFrame([
  ("2019-06-24T07:29:22.000+0000", "Image Quality: 75"),
  ("2019-06-25T07:29:22.000+0000", "Start scan"),
  ("2019-06-26T07:29:22.000+0000", "Image Quality: 95"),
  ("2019-06-27T07:29:22.000+0000", "Start scan"),
  ("2019-06-28T07:29:22.000+0000", "Start scan")  
], ["ts", "message"])
我感兴趣的是设计一个图像质量特性,即组成以下数据帧

+----------------------------+----------+-------------+
|ts                          |message   |image_quality|
+----------------------------+----------+-------------+
|2019-06-25T07:29:22.000+0000|Start scan|75           |
|2019-06-27T07:29:22.000+0000|Start scan|95           |
|2019-06-28T07:29:22.000+0000|Start scan|95           |
+----------------------------+----------+-------------+

我尝试了各种windows函数和子查询的组合,但似乎没有找到可行的解决方案。

IIUC,您希望将上一个可用的图像质量延续到下一个可用的图像质量

可以使用Windows尝试以下操作:

来自给定数据集的假设:对于任何日期,它总是从图像质量开始,然后是开始扫描

导入并准备数据集:

现在使用:分隔符和创建图像质量列拆分消息

使用orderBy ts列定义窗口

注意:由于我们对解决方案方法感兴趣,所以没有添加任何partitionBy列,但如果可能,则始终使用partitionBy

Spark还将发出以下警告:

警告WindowExec:没有为窗口操作定义分区!移动所有 将数据传输到单个分区,这可能会导致严重的性能问题 退化

最终数据集准备:

现在,应用窗口并使用last'col'查找最后一个可用的图像质量,True。此处True将忽略空值

另外,过滤记录并删除不喜欢的图像质量或==开始扫描


这正是我的目标,谢谢。请详细说明分区警告消息,因为我的实际数据集约为3亿行。在您的情况下,如果dataframe中只有2列,则我无法找到任何分区列组合达到相同的结果。@MaximVeksler:很高兴这有帮助。好的,警告说数据将被移动到一个分区中。这意味着没有多个分区,因此几乎没有来自spark的并发任务。另外,一个包含大量数据的分区可能会有来自内存、CPU、洗牌等方面的开销。因为您有大约3亿条记录,所以使用partitionBy是必需的。不确定是否有任何其他列可用作窗口,您可以使用基于数据的任何逻辑窗口。
# Import Window
from pyspark.sql.window import Window
import pyspark.sql.functions as f

df.show(10, False)
+----------------------------+-----------------+
|ts                          |message          |
+----------------------------+-----------------+
|2019-06-24T07:29:22.000+0000|Image Quality: 75|
|2019-06-25T07:29:22.000+0000|Start scan       |
|2019-06-26T07:29:22.000+0000|Image Quality: 95|
|2019-06-27T07:29:22.000+0000|Start scan       |
|2019-06-28T07:29:22.000+0000|Start scan       |
+----------------------------+-----------------+
df1 = df.withColumn('image_quality', f.split('message', ':')[1])
df1.show(10, False)
+----------------------------+-----------------+-------------+
|ts                          |message          |image_quality|
+----------------------------+-----------------+-------------+
|2019-06-24T07:29:22.000+0000|Image Quality: 75| 75          |
|2019-06-25T07:29:22.000+0000|Start scan       |null         |
|2019-06-26T07:29:22.000+0000|Image Quality: 95| 95          |
|2019-06-27T07:29:22.000+0000|Start scan       |null         |
|2019-06-28T07:29:22.000+0000|Start scan       |null         |
+----------------------------+-----------------+-------------+

w_spec = Window.orderBy('ts')
final_df = df1.withColumn('image_quality', f.coalesce('image_quality', f.last('image_quality', True).over(w_spec))) \
            .where(df1.message == 'Start scan')

final_df.show()

+--------------------+----------+-------------+
|                  ts|   message|image_quality|
+--------------------+----------+-------------+
|2019-06-25T07:29:...|Start scan|           75|
|2019-06-27T07:29:...|Start scan|           95|
|2019-06-28T07:29:...|Start scan|           95|
+--------------------+----------+-------------+