计算Pyspark中的滚动百分位数

时间:2019-10-11 17:11:50

标签: python pandas pyspark

我有一个带有日期,ID(比方说一个城市)和两列温度的数据框(在我的实际数据框中,我有一打列要计算)。

我想对给定窗口的温度进行“排序”。我希望此排名从0(窗口的最低温度)到100(同一窗口的最高温度)缩放。窗口必须是对称的(这意味着我要考虑之前和之后的几天)。我的测试数据框如下所示:

+-----------+-------+-----------------+-----------------+
|DATE_TICKET|ID_SITE|MAX_TEMPERATURE_C|MIN_TEMPERATURE_C|
+-----------+-------+-----------------+-----------------+
| 2017-03-24|    001|               22|               10|
| 2017-03-25|    001|               25|               15|
| 2017-03-26|    001|               31|               19|
| 2017-03-27|    001|               29|               18|
| 2017-03-28|    001|               30|               16|
| 2017-03-29|    001|               25|               17|
| 2017-03-30|    001|               24|               16|
| 2017-03-24|    002|               18|               12|
| 2017-03-25|    002|               17|               11|
| 2017-03-27|    002|               15|                7|
| 2017-03-28|    002|               12|                5|
| 2017-03-29|    002|                8|                3|
| 2017-03-30|    002|               10|                1|
| 2017-03-31|    002|               15|                4|
| 2017-03-24|    003|               18|                7|
| 2017-03-26|    003|               22|               11|
| 2017-03-27|    003|               27|               12|
| 2017-03-28|    003|               29|               15|
| 2017-04-01|    003|               31|               16|
| 2017-04-04|    003|               34|               22|
+-----------+-------+-----------------+-----------------+

要重新创建我的数据,可以使用以下代码:

data = {'DATE_TICKET': ['2017-03-24','2017-03-25','2017-03-26','2017-03-27','2017-03-28','2017-03-29','2017-03-30',
                 '2017-03-24','2017-03-25','2017-03-27','2017-03-28','2017-03-29','2017-03-30','2017-03-31',
                 '2017-03-24','2017-03-26','2017-03-27','2017-03-28','2017-04-01','2017-04-04'],
    'ID_SITE': ['001','001','001','001','001','001','001','002','002','002','002','002','002','002','003','003','003','003','003','003'],
        'MAX_TEMPERATURE_C': [22,25,31,29,30,25,24,18,17,15,12,8,10,15,18,22,27,29,31,34],
        'MIN_TEMPERATURE_C' : [10,15,19,18,16,17,16,12,11,7,5,3,1,4,7,11,12,15,16,22]}
df = pd.DataFrame(data)
ddf = ctx.createDataFrame(df)
ddf = ddf.withColumn('DATE_TICKET', ddf['DATE_TICKET'].cast('date'))

此刻我的代码如下:

import pandas as pd
import pyspark
import pyspark.sql.functions as F
import pyspark.sql.types as T
from pyspark.sql.window import Window
from pyspark.sql.types import FloatType

window_size = 2
target =  int((window_size)-0.5)

w = Window.partitionBy("ID_SITE").orderBy("DATE_TICKET").rowsBetween(-(window_size), window_size)

median_udf = F.udf(lambda x: float(np.median(x)), FloatType())

rank_udf = F.udf(lambda x: pd.cut(x, 101, include_lowest=True, labels=list(range(0,101)))[target])


ddf.withColumn("list", F.collect_list("MAX_TEMPERATURE_C").over(w)) \
  .withColumn("rolling_median", median_udf("list")).show(truncate = False)

这与'median_udf'函数一起工作(顺便说一句,我是从stackoverflow上的另一篇文章中复制/粘贴的)。但是此功能不能满足我的期望。

我想使用rank_udf函数,当我将其应用于单个列表时,它可以正常工作。它对给定窗口的所有值进行排名,并返回一个我感兴趣的单个值,即中间的一个。

例如:

data = [22,25,31,29,31,34,26,21]
target =  int((len(data)/2)-0.5)
pd.cut(data, 101, include_lowest=True, labels=list(range(0,101)))[target]

但是:

  • 首先,当我将其用作pyspark中的udf时,它会返回错误。
  • 即使没有错误,我也正在使用Pandas函数,并且希望能够在不使用pandas库的情况下做到这一点,因为我正在处理亿万行,并且我需要性能。

我尝试使用pyspark.ml.feature中的Bucketizer或QuantileDiscretizer之类的功能,但是我无法使其正常工作...

(PS:是的,我确实知道它并不是真正的百分位数,因为我使用的是101个垃圾箱而不是100个垃圾箱)

(PPS:如果您需要更多上下文/信息,我将编辑此帖子。)

0 个答案:

没有答案