0


pyspark 笔记:窗口函数window

窗口函数相关的概念和基本规范可以见:pyspark笔记:over-CSDN博客

1 创建Pyspark dataFrame

  1. from pyspark.sql.window import Window
  2. import pyspark.sql.functions as F
  1. employee_salary = [
  2. ("Ali", "Sales", 8000),
  3. ("Bob", "Sales", 7000),
  4. ("Cindy", "Sales", 7500),
  5. ("Davd", "Finance", 10000),
  6. ("Elena", "Sales", 8000),
  7. ("Fancy", "Finance", 12000),
  8. ("George", "Finance", 11000),
  9. ("Haffman", "Marketing", 7000),
  10. ("Ilaja", "Marketing", 8000),
  11. ("Joey", "Sales", 9000)]
  12. columns= ["name", "department", "salary"]
  13. df = spark.createDataFrame(data = employee_salary, schema = columns)
  14. df.show(truncate=False)

2 定义窗口规范

  1. partitionBy

作为分组条件,

  1. orderBy

  1. Window

分组内的数据进行排序

  1. # 以 department 字段进行分组,以 salary 倒序排序
  2. # 按照部门对薪水排名,薪水最低的为第一名
  3. windowSpec = Window.partitionBy("department").orderBy(F.asc("salary"))

后面的示例如无特殊说明,都是使用这个窗口规范

3 排名相关

3.1

  1. row_number()

用于给出从1开始到每个窗口分区的结果的连续行号

  1. df_part = df.withColumn(
  2. "row_number",
  3. F.row_number().over(windowSpec)
  4. )
  5. df_part.show()

[观察上面的数据,发现同样的薪水会有不同的排名(比如Ali和Elena,都是8000的薪水,但一个第三一个第四),这是因为

  1. row_number()

是按照行来给定序号,其不关注实际数值的大小。

3.1.1 应用举例:

找出每个department 薪水第二低的:

  1. df_part.where(F.col('row_number')==2).show()
  2. '''
  3. +------+----------+------+----------+
  4. | name|department|salary|row_number|
  5. +------+----------+------+----------+
  6. |George| Finance| 11000| 2|
  7. | Ilaja| Marketing| 8000| 2|
  8. | Cindy| Sales| 7500| 2|
  9. +------+----------+------+----------+
  10. '''

3.2 rank

不同于row_number,相同value的给相同值

  1. df_part = df.withColumn('rank_number',F.rank().over(windowSpec))
  2. df_part.show()
  3. '''
  4. +-------+----------+------+-----------+
  5. | name|department|salary|rank_number|
  6. +-------+----------+------+-----------+
  7. | Davd| Finance| 10000| 1|
  8. | George| Finance| 11000| 2|
  9. | Fancy| Finance| 12000| 3|
  10. |Haffman| Marketing| 7000| 1|
  11. | Ilaja| Marketing| 8000| 2|
  12. | Bob| Sales| 7000| 1|
  13. | Cindy| Sales| 7500| 2|
  14. | Ali| Sales| 8000| 3|
  15. | Elena| Sales| 8000| 3|
  16. | Joey| Sales| 9000| 5|
  17. +-------+----------+------+-----------+
  18. '''

可以看到在rank下,Ali和Elena的rank_number是一样的了

3.3 dense rank

先看结果,再看和rank的区别

  1. df_part = df.withColumn('dense_rank_number',F.dense_rank().over(windowSpec))
  2. df_part.show()
  3. +-------+----------+------+-----------------+
  4. | name|department|salary|dense_rank_number|
  5. +-------+----------+------+-----------------+
  6. | Davd| Finance| 10000| 1|
  7. | George| Finance| 11000| 2|
  8. | Fancy| Finance| 12000| 3|
  9. |Haffman| Marketing| 7000| 1|
  10. | Ilaja| Marketing| 8000| 2|
  11. | Bob| Sales| 7000| 1|
  12. | Cindy| Sales| 7500| 2|
  13. | Ali| Sales| 8000| 3|
  14. | Elena| Sales| 8000| 3|
  15. | Joey| Sales| 9000| 4|
  16. +-------+----------+------+-----------------+

我们重点看Joey(最后一行),rank中Ali和Elena并列第三后,身后的Joey排名第五;dense_rank中,Joey紧跟着排第四

3.4 percent_rank

百分位排名

  1. df_part = df.withColumn('percent_rank_number',F.percent_rank().over(windowSpec))
  2. df_part.show()
  3. '''
  4. +-------+----------+------+-------------------+
  5. | name|department|salary|percent_rank_number|
  6. +-------+----------+------+-------------------+
  7. | Davd| Finance| 10000| 0.0|
  8. | George| Finance| 11000| 0.5|
  9. | Fancy| Finance| 12000| 1.0|
  10. |Haffman| Marketing| 7000| 0.0|
  11. | Ilaja| Marketing| 8000| 1.0|
  12. | Bob| Sales| 7000| 0.0|
  13. | Cindy| Sales| 7500| 0.25|
  14. | Ali| Sales| 8000| 0.5|
  15. | Elena| Sales| 8000| 0.5|
  16. | Joey| Sales| 9000| 1.0|
  17. +-------+----------+------+-------------------+
  18. '''

3.5 ntile

  • ntile()可将分组的数据按照指定数值n切分为n个部分, 每一部分按照行的先后给定相同的序数。
  • 例如n指定为2,则将组内数据分为两个部分, 第一部分序号为1,第二部分序号为2。
  • 理论上两部分数据行数是均等的, 但当数据为奇数行时,中间的那一行归到前一部分。
  1. df_part = df.withColumn('ntile(2)',F.ntile(2).over(windowSpec))
  2. df_part.show()
  3. '''
  4. +-------+----------+------+--------+
  5. | name|department|salary|ntile(2)|
  6. +-------+----------+------+--------+
  7. | Davd| Finance| 10000| 1|
  8. | George| Finance| 11000| 1|
  9. | Fancy| Finance| 12000| 2|
  10. |Haffman| Marketing| 7000| 1|
  11. | Ilaja| Marketing| 8000| 2|
  12. | Bob| Sales| 7000| 1|
  13. | Cindy| Sales| 7500| 1|
  14. | Ali| Sales| 8000| 1|
  15. | Elena| Sales| 8000| 2|
  16. | Joey| Sales| 9000| 2|
  17. +-------+----------+------+--------+
  18. '''

4 分析相关函数

4.1

  1. cume_dist

数值的累进分布值

  1. df.withColumn('cum_dist',F.cume_dist().over(windowSpec)).show()
  2. '''
  3. +-------+----------+------+------------------+
  4. | name|department|salary| cum_dist|
  5. +-------+----------+------+------------------+
  6. | Davd| Finance| 10000|0.3333333333333333|
  7. | George| Finance| 11000|0.6666666666666666|
  8. | Fancy| Finance| 12000| 1.0|
  9. |Haffman| Marketing| 7000| 0.5|
  10. | Ilaja| Marketing| 8000| 1.0|
  11. | Bob| Sales| 7000| 0.2|
  12. | Cindy| Sales| 7500| 0.4|
  13. | Ali| Sales| 8000| 0.8|
  14. | Elena| Sales| 8000| 0.8|
  15. | Joey| Sales| 9000| 1.0|
  16. +-------+----------+------+------------------+
  17. '''

这个表怎么解读呢?以Sales为例,薪资小于等于7000的占比0.2,薪资小于等于7500的占比0.4,以此类推

4.2 lag

照指定列排好序的分组内每个数值的上一个数值

  1. df.withColumn('lag',F.lag('name').over(windowSpec)).show()
  2. '''
  3. +-------+----------+------+-------+
  4. | name|department|salary| lag|
  5. +-------+----------+------+-------+
  6. | Davd| Finance| 10000| null|
  7. | George| Finance| 11000| Davd|
  8. | Fancy| Finance| 12000| George|
  9. |Haffman| Marketing| 7000| null|
  10. | Ilaja| Marketing| 8000|Haffman|
  11. | Bob| Sales| 7000| null|
  12. | Cindy| Sales| 7500| Bob|
  13. | Ali| Sales| 8000| Cindy|
  14. | Elena| Sales| 8000| Ali|
  15. | Joey| Sales| 9000| Elena|
  16. +-------+----------+------+-------+
  17. '''

4.3 lead

和lag相反,下一个值

  1. df.withColumn('lead',F.lead('name').over(windowSpec)).show()
  2. '''
  3. +-------+----------+------+------+
  4. | name|department|salary| lead|
  5. +-------+----------+------+------+
  6. | Davd| Finance| 10000|George|
  7. | George| Finance| 11000| Fancy|
  8. | Fancy| Finance| 12000| null|
  9. |Haffman| Marketing| 7000| Ilaja|
  10. | Ilaja| Marketing| 8000| null|
  11. | Bob| Sales| 7000| Cindy|
  12. | Cindy| Sales| 7500| Ali|
  13. | Ali| Sales| 8000| Elena|
  14. | Elena| Sales| 8000| Joey|
  15. | Joey| Sales| 9000| null|
  16. +-------+----------+------+------+
  17. '''

5 聚合函数

此时的聚合样式为:

  1. windowSpecAgg=Window.partitionBy('department')

5.1 avg

平均值

  1. df.withColumn('avg',F.avg('salary').over(windowSpecAgg)).show()
  2. '''
  3. +-------+----------+------+-------+
  4. | name|department|salary| avg|
  5. +-------+----------+------+-------+
  6. | Davd| Finance| 10000|11000.0|
  7. | Fancy| Finance| 12000|11000.0|
  8. | George| Finance| 11000|11000.0|
  9. |Haffman| Marketing| 7000| 7500.0|
  10. | Ilaja| Marketing| 8000| 7500.0|
  11. | Ali| Sales| 8000| 7900.0|
  12. | Bob| Sales| 7000| 7900.0|
  13. | Cindy| Sales| 7500| 7900.0|
  14. | Elena| Sales| 8000| 7900.0|
  15. | Joey| Sales| 9000| 7900.0|
  16. +-------+----------+------+-------+
  17. '''

5.2 sum 求和

5.3 min/max 最大最小值

5.4 count 这一个窗口内有多少记录

  1. df.withColumn('count',F.count('salary').over(windowSpecAgg)).show()
  2. '''
  3. +-------+----------+------+-----+
  4. | name|department|salary|count|
  5. +-------+----------+------+-----+
  6. | Davd| Finance| 10000| 3|
  7. | Fancy| Finance| 12000| 3|
  8. | George| Finance| 11000| 3|
  9. |Haffman| Marketing| 7000| 2|
  10. | Ilaja| Marketing| 8000| 2|
  11. | Ali| Sales| 8000| 5|
  12. | Bob| Sales| 7000| 5|
  13. | Cindy| Sales| 7500| 5|
  14. | Elena| Sales| 8000| 5|
  15. | Joey| Sales| 9000| 5|
  16. +-------+----------+------+-----+
  17. '''

5.5 approx_count_distinct 相同的值只记录一次

  1. df.withColumn('ap_count',F.approx_count_distinct('salary').over(windowSpecAgg)).show()
  2. '''
  3. +-------+----------+------+--------+
  4. | name|department|salary|ap_count|
  5. +-------+----------+------+--------+
  6. | Davd| Finance| 10000| 3|
  7. | Fancy| Finance| 12000| 3|
  8. | George| Finance| 11000| 3|
  9. |Haffman| Marketing| 7000| 2|
  10. | Ilaja| Marketing| 8000| 2|
  11. | Ali| Sales| 8000| 4|
  12. | Bob| Sales| 7000| 4|
  13. | Cindy| Sales| 7500| 4|
  14. | Elena| Sales| 8000| 4|
  15. | Joey| Sales| 9000| 4|
  16. +-------+----------+------+--------+
  17. '''

参考内容:【PySpark】窗口函数Window - 知乎

标签: 笔记

本文转载自: https://blog.csdn.net/qq_40206371/article/details/135654854
版权归原作者 UQI-LIUWJ 所有, 如有侵权,请联系我们删除。

“pyspark 笔记:窗口函数window”的评论:

还没有评论