Pyspark:如何编写复杂的数据帧计算前置和

Pyspark:如何编写复杂的数据帧计算前置和,pyspark,apache-spark-sql,pyspark-dataframes,Pyspark,Apache Spark Sql,Pyspark Dataframes,我已经给出了看起来像这样的数据帧。 这个数据框是按日期排序的,col1只是一些随机值 TEST_schema = StructType([StructField("date", StringType(), True),\ StructField("col1", IntegerType(), True),\ ]) TEST_d

我已经给出了看起来像这样的数据帧。 这个数据框是按日期排序的,col1只是一些随机值

    TEST_schema = StructType([StructField("date", StringType(), True),\
                              StructField("col1", IntegerType(), True),\
                             ])
    TEST_data = [('2020-08-01',3),('2020-08-02',1),('2020-08-03',-1),('2020-08-04',-1),('2020-08-05',3),\
                 ('2020-08-06',-1),('2020-08-07',6),('2020-08-08',4),('2020-08-09',5)]
    rdd3 = sc.parallelize(TEST_data)
    TEST_df = sqlContext.createDataFrame(TEST_data, TEST_schema)
    TEST_df.show() 
    
+----------+----+
|      date|col1|
+----------+----+
|2020-08-01|   3|
|2020-08-02|   1|
|2020-08-03|  -1|
|2020-08-04|  -1|
|2020-08-05|   3|
|2020-08-06|  -1|
|2020-08-07|   6|
|2020-08-08|   4|
|2020-08-09|   5|
+----------+----+
逻辑:前导(col1)+1,如果col1==-1,则从上一个值前导(col1)+2…
结果数据帧如下所示(want列是我想要的输出)

让我们看看最后一行,其中col1==5,5是leaded+1,这是want==6(2020-08-08) 如果我们有col==-1,那么我们再加+1,如果我们有col==-1重复两次,那么我们再加+2。。 这很难用语言来解释,最后,因为它创建了最后一列而不是null,所以用-1替换。我有一张图表


您可以检查以下代码和逻辑是否适用于您:

  • 创建一个子组标签
    g
    ,它取运行总和
    int(col1!=-1)
    ,我们只关注col1=-1的行,并将所有其他行置为空
  • 剩余值为1,如果col1==-1,加上窗口
    w2
  • 将prev_col1置于
    w1
    之上,它不是-1(使用),(prev_col1的命名可能会混淆,因为它仅在col1=-1时使用典型的pyspark方法进行ffill,否则保留原始名称)
  • 设置val=prev_col1+残差,取滞后值并将null设置为-1
  • 代码如下:

    from pyspark.sql.functions import when, col, expr, count, desc, lag, coalesce    
    from pyspark.sql import Window
    
    w1 = Window.orderBy(desc('date'))
    w2 = Window.partitionBy('g').orderBy(desc('date'))  
    
    TEST_df.withColumn('g', when(col('col1') == -1, expr("sum(int(col1!=-1))").over(w1))) \
        .withColumn('residual', when(col('col1') == -1, count('*').over(w2) + 1).otherwise(1)) \
        .withColumn('prev_col1',expr("last(nullif(col1,-1),True)").over(w1)) \
        .withColumn('want', coalesce(lag(expr("prev_col1 + residual")).over(w1),lit(-1))) \
        .orderBy('date').show()
    +----------+----+----+--------+---------+----+
    |      date|col1|   g|residual|prev_col1|want|
    +----------+----+----+--------+---------+----+
    |2020-08-01|   3|null|       1|        3|   2|
    |2020-08-02|   1|null|       1|        1|   6|
    |2020-08-03|  -1|   4|       3|        3|   5|
    |2020-08-04|  -1|   4|       2|        3|   4|
    |2020-08-05|   3|null|       1|        3|   8|
    |2020-08-06|  -1|   3|       2|        6|   7|
    |2020-08-07|   6|null|       1|        6|   5|
    |2020-08-08|   4|null|       1|        4|   6|
    |2020-08-09|   5|null|       1|        5|  -1|
    +----------+----+----+--------+---------+----+
    

    您可以检查以下代码和逻辑是否适用于您:

  • 创建一个子组标签
    g
    ,它取运行总和
    int(col1!=-1)
    ,我们只关注col1=-1的行,并将所有其他行置为空
  • 剩余值为1,如果col1==-1,加上窗口
    w2
  • 将prev_col1置于
    w1
    之上,它不是-1(使用),(prev_col1的命名可能会混淆,因为它仅在col1=-1时使用典型的pyspark方法进行ffill,否则保留原始名称)
  • 设置val=prev_col1+残差,取滞后值并将null设置为-1
  • 代码如下:

    from pyspark.sql.functions import when, col, expr, count, desc, lag, coalesce    
    from pyspark.sql import Window
    
    w1 = Window.orderBy(desc('date'))
    w2 = Window.partitionBy('g').orderBy(desc('date'))  
    
    TEST_df.withColumn('g', when(col('col1') == -1, expr("sum(int(col1!=-1))").over(w1))) \
        .withColumn('residual', when(col('col1') == -1, count('*').over(w2) + 1).otherwise(1)) \
        .withColumn('prev_col1',expr("last(nullif(col1,-1),True)").over(w1)) \
        .withColumn('want', coalesce(lag(expr("prev_col1 + residual")).over(w1),lit(-1))) \
        .orderBy('date').show()
    +----------+----+----+--------+---------+----+
    |      date|col1|   g|residual|prev_col1|want|
    +----------+----+----+--------+---------+----+
    |2020-08-01|   3|null|       1|        3|   2|
    |2020-08-02|   1|null|       1|        1|   6|
    |2020-08-03|  -1|   4|       3|        3|   5|
    |2020-08-04|  -1|   4|       2|        3|   4|
    |2020-08-05|   3|null|       1|        3|   8|
    |2020-08-06|  -1|   3|       2|        6|   7|
    |2020-08-07|   6|null|       1|        6|   5|
    |2020-08-08|   4|null|       1|        4|   6|
    |2020-08-09|   5|null|       1|        5|  -1|
    +----------+----+----+--------+---------+----+
    

    回答得好+回答得好+1.