我通过一个例子来解释我的问题:
让我们假设我们有一个如下数据框:
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|
+---+-----+
并假设我想使用prices
为每个key
获取window
的列表:
w = Window.partitionBy('key')
original_df.withColumn('price_list', F.collect_list('price').over(w)).show()
输出:
+---+-----+----------------+
|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]|
+---+-----+----------------+
到目前为止一切都很好。
但是,如果要获取有序列表,然后将orderBy
添加到窗口w
中,我将得到:
w = Window.partitionBy('key').orderBy('price')
original_df.withColumn('ordered_list', F.collect_list('price').over(w)).show()
输出:
+---+-----+----------------+
|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
以这种方式影响window
吗?
答案 0 :(得分:3)
Spark窗口由三个部分指定:分区,顺序和框架。
专门针对您的问题,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]|
+---+-----+----------------+
答案 1 :(得分:1)
@ManojSingh的回答是完美的。我仍然想分享自己的观点,以便为您提供帮助。
Window.partitionBy('key')
的作用类似于数据框中每个groupBy
的{{1}},使您可以对所有key
执行相同的操作。
orderBy
通常在可排序的列中执行时才有意义。以一个名为'month'
的列为例,该列包含一年中的所有月份(1,2,3 ... 12),另外一个名为'price'
的列具有每个月的价格。如果要求和,均值或每个月以及前面所有值的总和,请使用orderBy
。例如,这可以很好地计算月份之间的差异。