【问题标题】:Pyspark advanced window functionPyspark 高级窗口函数
【发布时间】:2019-09-21 21:14:49
【问题描述】:

这是我的数据框:

FlightDate=[20,40,51,50,60,15,17,37,36,50]
IssuingDate=[10,15,44,45,55,10,2,30,32,24]
Revenue = [100,50,40,70,60,40,30,100,200,100]
Customer = ['a','a','a','a','a','b','b','b','b','b']
df = spark.createDataFrame(pd.DataFrame([Customer,FlightDate,IssuingDate, Revenue]).T, schema=["Customer",'FlightDate', 'IssuingDate','Revenue'])
df.show()

+--------+----------+-----------+-------+
|Customer|FlightDate|IssuingDate|Revenue|
+--------+----------+-----------+-------+
|       a|        20|         10|    100|
|       a|        40|         15|     50|
|       a|        51|         44|     40|
|       a|        50|         45|     70|
|       a|        60|         55|     60|
|       b|        15|         10|     40|
|       b|        27|          2|     30|
|       b|        37|         30|    100|
|       b|        36|         32|    200|
|       b|        50|         24|    100|
+--------+----------+-----------+-------+

为方便起见,我使用数字表示天数。

对于每个客户,我想将研究的 FlightDate 和研究的 FlightDate + 10 天之间的所有发行日期的收入相加。

也就是说:

  • 对于第一行:我将 IssuingDate 在第 20 天和第 30 天之间的所有收入相加...这里给出 0。
  • 对于第二行:我将 IssuingDate 第 40 天到第 50 天之间的所有收入相加,即 40+70 = 110

这是想要的结果:

+--------+----------+-----------+-------+------+
|Customer|FlightDate|IssuingDate|Revenue|Result|
+--------+----------+-----------+-------+------+
|       a|        20|         10|    100|     0|
|       a|        40|         15|     50|   110|
|       a|        51|         44|     40|    60|
|       a|        50|         45|     70|    60|
|       a|        60|         55|     60|     0|
|       b|        15|         10|     40|   100|
|       b|        27|          2|     30|   300|
|       b|        37|         30|    100|     0|
|       b|        36|         32|    200|     0|
|       b|        50|         24|    100|     0|
+--------+----------+-----------+-------+------+

我知道它会涉及一些窗口函数,但这个似乎有点棘手。谢谢

【问题讨论】:

  • IssuingDate 第 40 天到第 50 天之间的总收入,应该是 50 + 70 = 120?能否请你确认?同样对于第一行,您是否期望与特定行对应的值应为“100”,因为 forst 行中的收入为 100。或者您不包括 flightDate 20。
  • 嗨 neeraj,这里的想法是查看当前行的航班日期和当前行的航班日期 + 10 之间的发行日期的收入。

标签: python pyspark pyspark-sql window-functions


【解决方案1】:

不需要窗口函数。它只是一个 join 和一个 agg :

df.alias("df").join(
    df.alias("df_2"),
    on=F.expr(
        "df.Customer = df_2.Customer "
        "and df_2.issuingdate between df.flightdate and df.flightdate+10"
    ), 
    how='left'
).groupBy(
    *('df.{}'.format(c) 
      for c 
      in df.columns)
).agg(
    F.sum(F.coalesce(
        "df_2.revenue", 
        F.lit(0))
    ).alias("result")
).show()

+--------+----------+-----------+-------+------+                                
|Customer|FlightDate|IssuingDate|Revenue|result|
+--------+----------+-----------+-------+------+
|       a|        20|         10|    100|     0|
|       a|        40|         15|     50|   110|
|       a|        50|         45|     70|    60|
|       a|        51|         44|     40|    60|
|       a|        60|         55|     60|     0|
|       b|        15|         10|     40|   100|
|       b|        27|          2|     30|   300|
|       b|        36|         32|    200|     0|
|       b|        37|         30|    100|     0|
|       b|        50|         24|    100|     0|
+--------+----------+-----------+-------+------+

【讨论】:

  • 非常感谢,我正在想办法优化这个计算,因为我打算在一个巨大的数据帧(120M 行)上运行它
  • @plalanne On peut en discuter par Chat à l'occasion si besoin ;)
【解决方案2】:

如果您想保留当前行和接下来 10 天的收入,则可以使用以下代码。

例如

第一行:flightDate = 20,您需要介于 20 和 30(包括两个日期)之间的收入,这意味着总收入 = 100。

第二行:flightDate = 40,您需要在 40 和 50(包括两个日期)之间的收入,这意味着总收入 = 50(对于日期 40)+ 50(对于日期 50)= 120。

第三行:flightDate = 50,您需要在 50 和 60 之间(包括两个日期)的收入,这意味着总收入 = 70(对于日期 50)+ 40(对于日期 51)+ 60(对于日期 60)= 170

from pyspark.sql import *
from pyspark.sql.functions import *
import pandas as pd

FlightDate=[20,40,51,50,60,15,17,37,36,50]
IssuingDate=[10,15,44,45,55,10,2,30,32,24]
Revenue = [100,50,40,70,60,40,30,100,200,100]
Customer = ['a','a','a','a','a','b','b','b','b','b']
df = spark.createDataFrame(pd.DataFrame([Customer,FlightDate,IssuingDate, Revenue]).T, schema=["Customer",'FlightDate', 'IssuingDate','Revenue'])


windowSpec = Window.partitionBy("Customer").orderBy("FlightDate").rangeBetween(0,10)
df.withColumn("Sum", sum("Revenue").over(windowSpec)).sort("Customer").show()

结果如下所述

+--------+----------+-----------+-------+---+
|Customer|FlightDate|IssuingDate|Revenue|Sum|
+--------+----------+-----------+-------+---+
|       a|        20|         10|    100|100|
|       a|        40|         15|     50|120|
|       a|        50|         45|     70|170|
|       a|        51|         44|     40|100|
|       a|        60|         55|     60| 60|
|       b|        15|         10|     40| 70|
|       b|        17|          2|     30| 30|
|       b|        36|         32|    200|300|
|       b|        37|         30|    100|100|
|       b|        50|         24|    100|100|
+--------+----------+-----------+-------+---+

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-08-16
    • 2018-03-14
    • 2023-02-23
    • 2017-03-17
    • 2016-05-10
    • 2022-01-25
    • 2018-01-25
    • 2018-07-11
    相关资源
    最近更新 更多