【问题标题】:calculate the average by ignoring the 0 values in column通过忽略列中的 0 值来计算平均值
【发布时间】:2020-12-19 10:22:04
【问题描述】:

输入:

item   loc    month   year     qty    
watch  delhi   1       2020     10    
watch  delhi   2       2020     0     
watch  delhi   3       2020     20    
watch  delhi   4       2020     30    
watch  delhi   5       2020     40    
watch  delhi   6       2020     50 

输出:

item   loc    month   year     qty    avg
watch  delhi   1       2020     10    0
watch  delhi   2       2020     0     10
watch  delhi   3       2020     20    10
watch  delhi   4       2020     30    20
watch  delhi   5       2020     40    25
watch  delhi   6       2020     50    35

我们需要计算前两个月的平均值......但是计算平均值时需要一个条件......我们不需要考虑数量=0 同时计算平均值.....

例如:理想情况下,第 3 个月的平均值应为 10+0/2=5....但由于我们需要忽略 qty=0...所以第 3 个月的平均值为 10/1= 10....

提前致谢

【问题讨论】:

    标签: mysql sql dataframe apache-spark apache-spark-sql


    【解决方案1】:

    来自火花,

    val w = Window.partitionBy("item","loc").orderBy("month").rangeBetween(-2, -1)
    df.withColumn("month", 'month.cast("int"))
      .withColumn("avg", avg(when('qty =!= lit(0), 'qty)).over(w)).show()
    
    +-----+-----+-----+----+---+----+
    | item|  loc|month|year|qty| avg|
    +-----+-----+-----+----+---+----+
    |watch|delhi|    1|2020| 10| 0.0|
    |watch|delhi|    2|2020|  0|10.0|
    |watch|delhi|    3|2020| 20|10.0|
    |watch|delhi|    4|2020| 30|20.0|
    |watch|delhi|    5|2020| 40|25.0|
    |watch|delhi|    6|2020| 50|35.0|
    +-----+-----+-----+----+---+----+
    

    【讨论】:

    • 您的输出与第 6 个月的输出不匹配,平均值将为 30+40/2=35....我们在计算平均值时只需要考虑两个月
    • 只有两个?我明白了。
    • 我已经修改了 -2 和 -1 之间的范围,这意味着当前月份的平均值,例如第 6 个月由 -2 (4) 月和 -1 (5) 月的值计算。
    【解决方案2】:

    可以在使用lag函数和WindowFrame的spark中完成

    import org.apache.spark.sql.expressions.Window
    import org.apache.spark.sql.functions._
    import org.apache.spark.sql.types.IntegerType
    
    
    
    df.withColumn("month", col("month").cast(IntegerType))
    .withColumn("avg", when(lag("qty", 2, 0).over(w) =!= lit(0) && lag("qty", 1, 0).over(w) =!= lit(0),
    (lag("qty", 2, 0).over(w) + lag("qty", 1, 0).over(w)).divide(lit(2)))
    .when(lag("qty", 1, 0).over(w) =!= lit(0),lag("qty", 1, 0).over(w)).otherwise(lag("qty", 2, 0)
    .over(w))).show()
    

    输出:

    +-----+-----+-----+----+---+----+
    | item|  loc|month|year|qty| avg|
    +-----+-----+-----+----+---+----+
    |watch|delhi|    1|2020| 10|   0|
    |watch|delhi|    2|2020|  0|  10|
    |watch|delhi|    3|2020| 20|  10|
    |watch|delhi|    4|2020| 30|  20|
    |watch|delhi|    5|2020| 40|25.0|
    |watch|delhi|    6|2020| 50|35.0|
    +-----+-----+-----+----+---+----+
    

    【讨论】:

      【解决方案3】:

      在 SQL 中,您可以使用带有窗口框架说明符的窗口函数:

      select t.*,
             coalesce(avg(nullif(qty, 0)) over (partition by item, loc
                                                order by month
                                                rows between 2 preceding and 1 preceding
                                               ),
                      0) as qty_avg
      from t;
      

      【讨论】:

        【解决方案4】:

        我认为这是一个条件指数平均值:

        select 
            t.*,
            coalesce(avg(nullif(qty, 0)) over(partition by item, loc order by month), 0) qty_avg
        from mytable t
        

        nullif()0 值产生null - 然后avg() 忽略。我用coalesce() 包裹了整个窗口平均值,因为当只有null 值时,您似乎想要0

        【讨论】:

          猜你喜欢
          • 2021-04-16
          • 2020-09-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-05-15
          相关资源
          最近更新 更多