如何使用pyspark数据框窗口功能

时间:2020-11-06 15:30:37

标签: python dataframe apache-spark pyspark

我有一个如下数据框

enter image description here

我想获取一个具有最新日期的最新版本的数据框。第一个过滤条件是最新版本,然后是最新日期 产生的数据框应如下图所示

enter image description here

我正在使用窗口函数来实现此目的。我在下面的代码段中编写了

wind = Window.partitionBy("id")
data = data.withColumn("maxVersion", F.max("version").over(wind)) \
               .withColumn("maxDt", F.max("dt").over(wind)) \
               .where(F.col("version") == F.col("maxVersion")) \
               .where(F.col("maxDt") == F.col("dt")) \
               .drop(F.col("maxVersion")) \
               .drop(F.col("maxDt"))

我不确定我错过了什么,我只会得到一个ID为100的输出。 请帮我解决这个问题

3 个答案:

答案 0 :(得分:1)

基本上,您的配方有几个问题。 首先,您需要将日期从字符串更改为正确的日期格式。 然后pyspark中的Window允许您一个接一个地指定列的顺序。然后是df.col1.apply(type) Out[34]: 0 <class 'str'> 1 <class 'str'> 2 <class 'str'> 3 <class 'str'> Name: col1, dtype: object 函数,可让您在窗口上对结果进行排名。最后剩下的就是选择第一名。

rank()

输出:

from pyspark.sql.types import *
from pyspark import SparkContext, SQLContext
import pyspark.sql.functions as F
from pyspark.sql import Window

sc = SparkContext('local')
sqlContext = SQLContext(sc)

data1 = [
        (100,1,"2020-03-19","Nil1"),
        (100,2,"2020-04-19","Nil2"),
        (100,2,"2020-04-19","Nil2"),
        (100,2,"2020-05-19","Ni13"),
        (200,1,"2020-09-19","Jay1"),
        (200,2,"2020-07-19","Jay2"),
        (200,2,"2020-08-19","Jay3"),

      ]

df1Columns = ["id", "version", "dt",  "Name"]
df1 = sqlContext.createDataFrame(data=data1, schema = df1Columns)
df1 = df1.withColumn("dt",F.to_date(F.to_timestamp("dt", 'yyyy-MM-dd')).alias('dt'))
print("Schema.")
df1.printSchema()
print("Actual initial data")
df1.show(truncate=False)

wind = Window.partitionBy("id").orderBy(F.desc("version"), F.desc("dt"))

df1 = df1.withColumn("rank", F.rank().over(wind))
print("Ranking over the window spec specified")
df1.show(truncate=False)

final_df = df1.filter(F.col("rank") == 1).drop("rank")
print("Filtering the final result by applying the rank == 1 condition")
final_df.show(truncate=False)

答案 1 :(得分:0)

如前所述,您的操作符中有一个命令:第一个版本,然后是dt 基本上,您只需要选择最大版本(删除所有其他内容),然后选择maximum dt并删除其他所有内容。 您只需要这样切换两行即可:

int

为什么只获得id为100的一行,是因为在这种情况下,最高版本和最大dt发生在同一行上(您很幸运)。但是ID为200的情况并非如此。

答案 2 :(得分:0)

更整洁的方法可能是执行以下操作:

w = Window.partitionBy("id").orderBy(F.col('version').desc(), F.col('dt').desc())
df1.withColumn('maximum', F.row_number().over(w)).filter('maximum = 1').drop('maximum').show()