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|
+--------------------+----------+-------------+