orderBy如何影响Pyspark数据框架中的Window.partitionBy?
我通过一个例子来解释我的问题:orderBy如何影响Pyspark数据框架中的Window.partitionBy?,pyspark,window,sql-order-by,Pyspark,Window,Sql Order By,我通过一个例子来解释我的问题: 假设我们有一个数据帧,如下所示: original_df = sc.createDataFrame([('x', 10,), ('x', 15,), ('x', 10,), ('x', 25,), ('y', 20,), ('y', 10,), ('y', 20,)], ["key", "price"] ) original_df.show() 输出: +---+-----+ |key|price| +---+-----+ | x| 10| | x|
假设我们有一个数据帧,如下所示:
original_df = sc.createDataFrame([('x', 10,), ('x', 15,), ('x', 10,), ('x', 25,), ('y', 20,), ('y', 10,), ('y', 20,)], ["key", "price"] )
original_df.show()
输出:
+---+-----+
|key|price|
+---+-----+
| x| 10|
| x| 15|
| x| 10|
| x| 25|
| y| 20|
| y| 10|
| y| 20|
+---+-----+
+---+-----+----------------+
|key|price| price_list|
+---+-----+----------------+
| x| 10|[10, 15, 10, 25]|
| x| 15|[10, 15, 10, 25]|
| x| 10|[10, 15, 10, 25]|
| x| 25|[10, 15, 10, 25]|
| y| 20| [20, 10, 20]|
| y| 10| [20, 10, 20]|
| y| 20| [20, 10, 20]|
+---+-----+----------------+
+---+-----+----------------+
|key|price| ordered_list|
+---+-----+----------------+
| x| 10| [10, 10]|
| x| 10| [10, 10]|
| x| 15| [10, 10, 15]|
| x| 25|[10, 10, 15, 25]|
| y| 10| [10]|
| y| 20| [10, 20, 20]|
| y| 20| [10, 20, 20]|
+---+-----+----------------+
假设我想使用窗口获得每个键的价格列表
:
w = Window.partitionBy('key')
original_df.withColumn('price_list', F.collect_list('price').over(w)).show()
输出:
+---+-----+
|key|price|
+---+-----+
| x| 10|
| x| 15|
| x| 10|
| x| 25|
| y| 20|
| y| 10|
| y| 20|
+---+-----+
+---+-----+----------------+
|key|price| price_list|
+---+-----+----------------+
| x| 10|[10, 15, 10, 25]|
| x| 15|[10, 15, 10, 25]|
| x| 10|[10, 15, 10, 25]|
| x| 25|[10, 15, 10, 25]|
| y| 20| [20, 10, 20]|
| y| 10| [20, 10, 20]|
| y| 20| [20, 10, 20]|
+---+-----+----------------+
+---+-----+----------------+
|key|price| ordered_list|
+---+-----+----------------+
| x| 10| [10, 10]|
| x| 10| [10, 10]|
| x| 15| [10, 10, 15]|
| x| 25|[10, 10, 15, 25]|
| y| 10| [10]|
| y| 20| [10, 20, 20]|
| y| 20| [10, 20, 20]|
+---+-----+----------------+
到目前为止还不错。
但如果我想获得一个有序列表,并将orderBy
添加到我的窗口w
中,我会得到:
w = Window.partitionBy('key').orderBy('price')
original_df.withColumn('ordered_list', F.collect_list('price').over(w)).show()
输出:
+---+-----+
|key|price|
+---+-----+
| x| 10|
| x| 15|
| x| 10|
| x| 25|
| y| 20|
| y| 10|
| y| 20|
+---+-----+
+---+-----+----------------+
|key|price| price_list|
+---+-----+----------------+
| x| 10|[10, 15, 10, 25]|
| x| 15|[10, 15, 10, 25]|
| x| 10|[10, 15, 10, 25]|
| x| 25|[10, 15, 10, 25]|
| y| 20| [20, 10, 20]|
| y| 10| [20, 10, 20]|
| y| 20| [20, 10, 20]|
+---+-----+----------------+
+---+-----+----------------+
|key|price| ordered_list|
+---+-----+----------------+
| x| 10| [10, 10]|
| x| 10| [10, 10]|
| x| 15| [10, 10, 15]|
| x| 25|[10, 10, 15, 25]|
| y| 10| [10]|
| y| 20| [10, 20, 20]|
| y| 20| [10, 20, 20]|
+---+-----+----------------+
这意味着,orderBy
(某种程度上)也更改了窗口中的行(与rowsBetween
所做的相同)!这是不应该的
即使我可以通过在窗口中指定rowsBetween
来修复它,并获得预期的结果
w = Window.partitionBy('key').orderBy('price').rowsBetween(Window.unboundedPreceding, Window.unboundedFollowing)
有人能解释一下为什么orderBy
会以这种方式影响窗口吗?Spark窗口使用三个部分指定:分区、顺序和框架
如果未指定任何部分,则整个数据集将被视为单个窗口
当使用列指定分区时,将为列的每个不同值创建一个窗口。如果只指定了分区,那么当为一行计算WHE时,将考虑该分区中的所有行。这就是为什么您可以看到分区x中所有行的所有4个值[10,15,10,25]
如果指定了分区和排序,则在计算行函数时,它将采用分区中行的秩顺序,并包括具有相同或更低值(如果指定了默认asc顺序)秩的所有行。在您的例子中,第一行包括[10,10],因为分区中有两行具有相同的秩
当指定了帧规范rowsbeween和rangeBetween时,行求值将仅拾取与帧规则匹配的行。e、 g.如果指定了unbounded和currentRow,则它将拾取当前行及其之前出现的所有行。如果指定了orderBy,它将相应地更改在当前行之前出现的行
特别是针对您的问题,orderBy不仅用于对分区数据进行排序,还可以更改行帧选择
下面是不同的windowspec和相应的输出
Window.orderBy()
+---+-----+----------------------------+
|key|price|price_list |
+---+-----+----------------------------+
|x |15 |[15, 10, 10, 20, 10, 25, 20]|
|x |10 |[15, 10, 10, 20, 10, 25, 20]|
|y |10 |[15, 10, 10, 20, 10, 25, 20]|
|y |20 |[15, 10, 10, 20, 10, 25, 20]|
|x |10 |[15, 10, 10, 20, 10, 25, 20]|
|x |25 |[15, 10, 10, 20, 10, 25, 20]|
|y |20 |[15, 10, 10, 20, 10, 25, 20]|
+---+-----+----------------------------+
Window.partitionBy('key')
+---+-----+----------------+
|key|price| price_list|
+---+-----+----------------+
| x| 15|[15, 10, 10, 25]|
| x| 10|[15, 10, 10, 25]|
| x| 10|[15, 10, 10, 25]|
| x| 25|[15, 10, 10, 25]|
| y| 20| [20, 10, 20]|
| y| 10| [20, 10, 20]|
| y| 20| [20, 10, 20]|
+---+-----+----------------+
Window.partitionBy('key').orderBy('price')
+---+-----+----------------+
|key|price| ordered_list|
+---+-----+----------------+
| x| 10| [10, 10]|
| x| 10| [10, 10]|
| x| 15| [10, 10, 15]|
| x| 25|[10, 10, 15, 25]|
| y| 10| [10]|
| y| 20| [10, 20, 20]|
| y| 20| [10, 20, 20]|
+---+-----+----------------+
w = Window.partitionBy('key').orderBy(F.desc('price'))
+---+-----+----------------+
|key|price| ordered_list|
+---+-----+----------------+
| x| 25| [25]|
| x| 15| [25, 15]|
| x| 10|[25, 15, 10, 10]|
| x| 10|[25, 15, 10, 10]|
| y| 20| [20, 20]|
| y| 20| [20, 20]|
| y| 10| [20, 20, 10]|
+---+-----+----------------+
Window.partitionBy('key').orderBy('price').rowsBetween(Window.unboundedPreceding, Window.currentRow)
+---+-----+----------------+
|key|price| ordered_list|
+---+-----+----------------+
| x| 10| [10]|
| x| 10| [10, 10]|
| x| 15| [10, 10, 15]|
| x| 25|[10, 10, 15, 25]|
| y| 10| [10]|
| y| 20| [10, 20]|
| y| 20| [10, 20, 20]|
+---+-----+----------------+
Window.partitionBy('key').rowsBetween(Window.unboundedPreceding, Window.currentRow)
+---+-----+----------------+
|key|price| ordered_list|
+---+-----+----------------+
| x| 15| [15]|
| x| 10| [15, 10]|
| x| 10| [15, 10, 10]|
| x| 25|[15, 10, 10, 25]|
| y| 10| [10]|
| y| 20| [10, 20]|
| y| 20| [10, 20, 20]|
+---+-----+----------------+
@ManojSingh的答案是完美的。我仍然想分享我的观点,以便我能有所帮助
窗口.partitionBy('key')
对于数据帧中的每个不同的键
都像一个groupBy
一样工作,允许您对所有键执行相同的操作
当在可排序列中执行时,orderBy
通常是有意义的。例如,一个名为'month'
的列包含一年中的所有月份(1,2,3…12),另一个名为'price'
的列包含每个月的价格。如果您想计算每个月和之前所有月份的总和、平均值或其他值,可以使用orderBy
。例如,这对于计算月份之间的变化是很好的