【问题标题】:Pyspark - Calculate RMSE between actuals and predictions for a groupby - AssertionError: all exprs should be ColumnPyspark - 计算 groupby 的实际值和预测值之间的 RMSE - AssertionError: all exprs should be Column
【发布时间】:2020-04-13 02:24:37
【问题描述】:

我有一个函数可以计算整个数据帧的预测值和实际值的 RMSE:

def calculate_rmse(df, actual_column, prediction_column):
    RMSE = F.udf(lambda x, y: ((x - y) ** 2))
    df = df.withColumn(
        "RMSE", RMSE(F.col(actual_column), F.col(prediction_column))
    )
    rmse = df.select(F.avg("RMSE") ** 0.5).collect()
    rmse = rmse[0]["POWER(avg(RMSE), 0.5)"]
    return rmse

test = calculate_rmse(my_df, 'actuals', 'preds')

3690.4535

我想将此应用于groupby 语句,但是当我这样做时,我得到以下信息:

df_gb = my_df.groupby('start_month', 'start_week').agg(calculate_rmse(my_df, 'actuals', 'preds'))


all exprs should be Column
Traceback (most recent call last):
  File "/usr/lib/spark/python/lib/pyspark.zip/pyspark/sql/group.py", line 113, in agg
    assert all(isinstance(c, Column) for c in exprs), "all exprs should be Column"
AssertionError: all exprs should be Column

有人能指出我正确的方向吗?我对 Pyspark 还很陌生。

【问题讨论】:

    标签: python apache-spark pyspark apache-spark-sql pyspark-sql


    【解决方案1】:

    如果要按组计算RMSE,稍微改编一下我给your question提出的方案

    import pyspark.sql.functions as psf
    
    def compute_RMSE(expected_col, actual_col):
    
      rmse = old_df.withColumn("squarederror",
                               psf.pow(psf.col(actual_col) - psf.col(expected_col),
                                       psf.lit(2)
                               ))
      .groupby('start_month', 'start_week')
      .agg(psf.avg(psf.col("squarederror")).alias("mse"))
      .withColumn("rmse", psf.sqrt(psf.col("mse")))
    
      return(rmse)
    
    
    compute_RMSE("col1", "col2")
    

    【讨论】:

    • 我认为这非常接近,我认为我们需要取平方误差的平均值才能得到正确答案?
    • 很好 - 我的回答已经分解了步骤,但您将它们全部包含在一个表达式中,这是 groupby 所必需的。
    • 是的,你是对的,那是avg 不是sum 是必需的吗?我编辑结果
    【解决方案2】:

    我认为您不需要 UDF - 我认为您应该能够获取两列之间的差异 (df.withColumn('difference', col('true') - col('pred'))),然后计算该列的平方 (df.withColumn('squared_difference', pow(col('difference'), lit(2).astype(IntegerType()))),然后计算列的平均值 (df.withColumn('rmse', avg('squared_difference')))。用一个例子把它们放在一起:

    from pyspark.sql import SparkSession
    from pyspark.sql import SQLContext
    import pyspark.sql.functions as F
    from pyspark.sql.types import IntegerType
    
    spark = SparkSession.builder.getOrCreate()
    
    sql_context = SQLContext(spark.sparkContext)
    
    df = sql_context.createDataFrame([(0.0, 1.0),
                                      (1.0, 2.0),
                                      (3.0, 5.0),
                                      (1.0, 8.0)], schema=['true', 'predicted'])
    
    df = df.withColumn('difference', F.col('true') - F.col('predicted'))
    df = df.withColumn('squared_difference', F.pow(F.col('difference'), F.lit(2).astype(IntegerType())))
    rmse = df.select(F.avg(F.col('squared_difference')).alias('rmse'))
    
    print(df.show())
    print(rmse.show())
    

    输出:

    +----+---------+----------+------------------+
    |true|predicted|difference|squared_difference|
    +----+---------+----------+------------------+
    | 0.0|      1.0|      -1.0|               1.0|
    | 1.0|      2.0|      -1.0|               1.0|
    | 3.0|      5.0|      -2.0|               4.0|
    | 1.0|      8.0|      -7.0|              49.0|
    +----+---------+----------+------------------+
    
    +-----+
    | rmse|
    +-----+
    |13.75|
    +-----+
    

    希望这会有所帮助!

    编辑

    抱歉,我忘了取结果的平方根 - 最后一行变成:

    rmse = df.select(F.sqrt(F.avg(F.col('squared_difference'))).alias('rmse'))
    

    输出变为:

    +------------------+
    |              rmse|
    +------------------+
    |3.7080992435478315|
    +------------------+
    

    【讨论】:

    • 对于整个数据集,可以使用 Spark ML 在两行代码中计算 RMSE。但是 OP 希望在groupBy() 之后为每个单独的组计算它。
    • 是的,我刚刚意识到 - 我认为 linog 的答案是正确的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多