我想计算列percent_rank
的{{1}},但排名应仅相对于过去的值 - 由时间戳变量{{确定1}}。
似乎x
不接受任何参数,并且让排名与时间无关t
?!
有没有办法根据较小的时间戳的值来获得排名?
预期结果类似于
F.percent_rank()
答案 0 :(得分:1)
为了获得滚动percent_rank()
,您必须能够使用窗口框架定义来排序您根本无法进行的功能。 (像这样w = Window.orderBy('t', 'x').rowsBetween(-sys.maxsize, 0)
)
我找到了解决方法,但它涉及笛卡尔联合,这是非常昂贵的:
首先让我们创建示例数据框:
import pyspark.sql.functions as psf
from pyspark.sql import HiveContext
hc = HiveContext(sc)
df = hc.createDataFrame(sc.parallelize(zip(range(5), [1,3,5,4,2])), ['t', 'x'])
笛卡尔联盟:
df2 = df.groupBy(df.x.alias('x2')).agg(psf.min("t").alias("t2"))
df_cross = df.join(df2).filter("t2 <= t").withColumn("isSup", (df.x > df2.x2).cast("int"))
+---+---+---+---+-----+
| t| x| t2| x2|isSup|
+---+---+---+---+-----+
| 1| 3| 0| 1| 1|
| 2| 5| 0| 1| 1|
| 2| 5| 1| 3| 1|
| 3| 4| 0| 1| 1|
| 3| 4| 1| 3| 1|
| 3| 4| 2| 5| 0|
| 4| 2| 0| 1| 1|
| 4| 2| 1| 3| 0|
| 4| 2| 2| 5| 0|
| 4| 2| 3| 4| 0|
+---+---+---+---+-----+
最后我们按't'分组,'x':
df_fin = df_cross.groupBy("t", "x").agg(
psf.count("*").alias("count"),
psf.sum("isSup").alias("rank")
).withColumn('pct_rank_win', psf.col("rank")/psf.greatest(psf.col('count') - 1, psf.lit(1)))
+---+---+-----+----+------------------+
| t| x|count|rank| pct_rank_win|
+---+---+-----+----+------------------+
| 0| 1| 1| 0| 0.0|
| 1| 3| 2| 1| 1.0|
| 2| 5| 3| 2| 1.0|
| 3| 4| 4| 2|0.6666666666666666|
| 4| 2| 5| 1| 0.25|
+---+---+-----+----+------------------+
groupBy('x')
定义中的df2
是为了确保密集排名(相同的值具有相同的排名),如下例所示:
df = hc.createDataFrame(sc.parallelize(zip(range(6), [1,3,3,5,4,2])), ['t', 'x'])
+---+---+-----+----+------------------+
| t| x|count|rank| pct_rank_win|
+---+---+-----+----+------------------+
| 0| 1| 1| 0| 0.0|
| 1| 3| 2| 1| 1.0|
| 2| 3| 2| 1| 1.0|
| 3| 5| 3| 2| 1.0|
| 4| 4| 4| 2|0.6666666666666666|
| 5| 2| 5| 1| 0.25|
+---+---+-----+----+------------------+
答案 1 :(得分:1)
这是我尝试在窗口分区上使用collect_set的另一项工作,
{{1}}