Apache spark 如何创建与列大小相关的Pyspark窗口函数

Apache spark 如何创建与列大小相关的Pyspark窗口函数,apache-spark,pyspark,apache-spark-sql,window-functions,Apache Spark,Pyspark,Apache Spark Sql,Window Functions,尝试使用pyspark中的窗口函数在依赖于列的前几行上累积值时,我遇到了一个意外错误 下面是重现我遇到的错误的最小工作示例(MWE): from pyspark.sql import Window import pandas as pd df = sqlContext.createDataFrame( [("A", 0.1, pd.datetime(2020,12,1), 0), ("A"

尝试使用pyspark中的窗口函数在依赖于列的前几行上累积值时,我遇到了一个意外错误

下面是重现我遇到的错误的最小工作示例(MWE):

from pyspark.sql import Window
import pandas as pd

df = sqlContext.createDataFrame( [("A", 0.1, pd.datetime(2020,12,1), 0),
                                  ("A", 2.1, pd.datetime(2020,12,5), 3), 
                                  ("A", 1.1, pd.datetime(2020,12,7), 1), 
                                  ("A", 3.1, pd.datetime(2020,12,9), 3), 
                                 ],
                                 ["id", "value","timestamp", "previous_rows_to_consider"] )
df.show()
# +---+-----+-------------------+-------------------------+
# | id|value|          timestamp|previous_rows_to_consider|
# +---+-----+-------------------+-------------------------+
# |  A|  0.1|2020-12-01 00:00:00|                        0|
# |  A|  2.1|2020-12-05 00:00:00|                        3|
# |  A|  1.1|2020-12-07 00:00:00|                        1|
# |  A|  3.1|2020-12-09 00:00:00|                        3|
# +---+-----+-------------------+-------------------------+

import pyspark.sql.functions as F
w = Window.partitionBy('id').orderBy( F.col('timestamp') ).rowsBetween( -F.col('previous_rows_to_consider'),0 )

df = df.withColumn('value_cumsum_on_previous_rows', F.sum('value').over(w) )
df.show()
这将产生
ValueError:无法将列转换为布尔值:在构建数据帧布尔表达式时,请使用“&”表示“and”,使用“|”表示“or”,使用“~”表示“not”。

我还尝试了一些解决方法,使用
rangeBetween
而不是
rowsBetween
,但我得到了相同的错误

正如@murtihash在一篇相关文章中指出的,我确实怀疑
rowsBetween
/
rangeBetween
根本不接受列类型作为输入,但在一些在线资源中,我发现至少
rangeBetween
应该(例如,请参阅提供的概述)

  • 是否有人能够理解是什么阻止了我的MWE,或者确认
    介于
    行之间的范围
    仅接受整数值作为输入?
  • 如果是后一种情况,有人能建议一种解决方法来计算与列相关的范围/行数的累积和吗?

实际上,您不能将列放入范围/行窗口。作为一种变通方法(灵感来源于):


请注意,此解决方案适用于前面有行的窗口。如果需要跟随行,请删除
F.reverse

确实,您无法将列放入范围/行窗口。作为一种变通方法(灵感来源于):


请注意,此解决方案适用于前面有行的窗口。如果您需要以下行,请删除
F.reverse

我试图通过将
F.expr
的输入转换为“pure pyspark”来分解它,以便更好地理解单个步骤。我设法理解了这个命令的大部分功能。但是,我无法将该步骤转换为“纯pyspark”,因为(1)在
slice
之后,仅使用
F.expr
接受列输入;(2) 我找不到一种“纯pyspark”方法来对数组列的元素进行求和,这种方法不依赖于
F.expr('aggregate(…)')
。pyspark不支持所有Spark SQL函数,当它支持时,有时它不支持使用列作为参数。不幸的是,这是pyspark的一个限制,但幸运的是,我们总是可以使用F.exprAlso,因为我想它可能对像我这样不熟悉
F.expr
的人有用,让我在这里补充一下我对其用法的理解:(1)
slice
只需要前面的第一行就可以考虑值列表的元素,(2)
aggregate
,使用
(x,y)->x+y
第三个参数对结果列的元素进行汇总,(3)我猜
cast
要么指定聚合函数产生的列的类型,要么指定如何处理0/null值)。如果我错了,请告诉我。我认为你是对的。在没有演员阵容的情况下尝试,看看会出现什么错误;)这会告诉你演员阵容是什么好吧,我试过了,但我真的想不出来。看起来
cast
中的值类似于一种偏移量(如果我将0更改为标量值x,则列cumsum将被移位为x)。无论如何,在这一点上,我觉得一切都很好。谢谢!我试图通过将
F.expr
的输入转换为“pure pyspark”来分解它,以便更好地理解单个步骤。我设法理解了这个命令的大部分功能。但是,我无法将该步骤转换为“纯pyspark”,因为(1)在
slice
之后,仅使用
F.expr
接受列输入;(2) 我找不到一种“纯pyspark”方法来对数组列的元素进行求和,这种方法不依赖于
F.expr('aggregate(…)')
。pyspark不支持所有Spark SQL函数,当它支持时,有时它不支持使用列作为参数。不幸的是,这是pyspark的一个限制,但幸运的是,我们总是可以使用F.exprAlso,因为我想它可能对像我这样不熟悉
F.expr
的人有用,让我在这里补充一下我对其用法的理解:(1)
slice
只需要前面的第一行就可以考虑值列表的元素,(2)
aggregate
,使用
(x,y)->x+y
第三个参数对结果列的元素进行汇总,(3)我猜
cast
要么指定聚合函数产生的列的类型,要么指定如何处理0/null值)。如果我错了,请告诉我。我认为你是对的。在没有演员阵容的情况下尝试,看看会出现什么错误;)这会告诉你演员阵容是什么好吧,我试过了,但我真的想不出来。看起来
cast
中的值类似于一种偏移量(如果我将0更改为标量值x,则列cumsum将被移位为x)。无论如何,在这一点上,我觉得一切都很好。谢谢!
df2 = df.withColumn(
    'value_list', 
    F.reverse(
        F.collect_list('value').over(Window.partitionBy('id').orderBy('timestamp'))
    )
).withColumn(
    'cumsum',
    F.expr('''aggregate(
        slice(value_list, 1, previous_rows_to_consider + 1),
        cast(0 as double),
        (x, y) -> x + y
    )''')
)

df2.show()
+---+-----+-------------------+-------------------------+--------------------+------+
| id|value|          timestamp|previous_rows_to_consider|          value_list|cumsum|
+---+-----+-------------------+-------------------------+--------------------+------+
|  A|  0.1|2020-12-01 00:00:00|                        0|               [0.1]|   0.1|
|  A|  2.1|2020-12-05 00:00:00|                        3|          [2.1, 0.1]|   2.2|
|  A|  1.1|2020-12-07 00:00:00|                        1|     [1.1, 2.1, 0.1]|   3.2|
|  A|  3.1|2020-12-09 00:00:00|                        3|[3.1, 1.1, 2.1, 0.1]|   6.4|
+---+-----+-------------------+-------------------------+--------------------+------+