如何在Spark SQL中为每个组创建z-score

Bg1*_*850 6 python apache-spark apache-spark-sql pyspark

我有一个看起来像这样的数据框

        dSc     TranAmount
 1: 100021      79.64
 2: 100021      79.64
 3: 100021       0.16
 4: 100022      11.65
 5: 100022       0.36
 6: 100022       0.47
 7: 100025       0.17
 8: 100037       0.27
 9: 100056       0.27
10: 100063       0.13
11: 100079       0.13
12: 100091       0.15
13: 100101       0.22
14: 100108       0.14
15: 100109       0.04
Run Code Online (Sandbox Code Playgroud)

现在我想创建一个第三列,每个列的z分数TranAmount都是

(TranAmount-mean(TranAmount))/StdDev(TranAmount)
Run Code Online (Sandbox Code Playgroud)

这里的平均值和标准偏差将基于每个dSc的组

现在我可以计算Spark SQL中的均值和标准差.

(datafromdb
  .groupBy("dSc")
  .agg(datafromdb.dSc, func.avg("TranAmount") ,func.stddev_pop("TranAmount")))
Run Code Online (Sandbox Code Playgroud)

但我对如何在数据框中获得z-score的第三列感到茫然.我希望任何指向正确的方法来实现这个/

zer*_*323 8

例如,您可以join使用原始数据计算统计信息:

stats = (df.groupBy("dsc")
  .agg(
      func.stddev_pop("TranAmount").alias("sd"), 
      func.avg("TranAmount").alias("avg")))

df.join(broadcast(stats), ["dsc"])

(df
    .join(func.broadcast(stats), ["dsc"])
    .select("dsc", "TranAmount", (df.TranAmount - stats.avg) / stats.sd))
Run Code Online (Sandbox Code Playgroud)

或使用标准差公式的窗口函数:

from pyspark.sql.window import Window
import sys

def z_score_w(col, w):
    avg_ = func.avg(col).over(w)
    avg_sq = func.avg(col * col).over(w)
    sd_ = func.sqrt(avg_sq - avg_ * avg_)
    return (col - avg_) / sd_

w = Window().partitionBy("dsc").rowsBetween(-sys.maxsize, sys.maxsize)
df.withColumn("zscore", z_score_w(df.TranAmount, w))
Run Code Online (Sandbox Code Playgroud)

  • 它等同于"无约束前进和无约束下行"条款. (2认同)