如何在 PySpark SQL 中实现用户定义的聚合函数 (UDAF)?
pyspark version = 3.0.2
python version = 3.7.10
作为一个最小的例子,我想用 UDAF 替换 AVG 聚合函数:
sc = SparkContext()
sql = SQLContext(sc)
df = sql.createDataFrame(
pd.DataFrame({'id': [1, 1, 2, 2], 'value': [1, 2, 3, 4]}))
df.createTempView('df')
rv = sql.sql('SELECT id, AVG(value) FROM df GROUP BY id').toPandas()
rv 的位置:
In [2]: rv
Out[2]:
id avg(value)
0 1 1.5
1 2 3.5
UDAF 如何替换查询中的 AVG
?
例如这不起作用
import numpy as np
def udf_avg(x):
return np.mean(x)
sql.udf.register('udf_avg', udf_avg)
rv = sql.sql('SELECT id, udf_avg(value) FROM df GROUP BY id').toPandas()
这个想法是在纯 Python 中实现 UDAF,用于处理 SQL 聚合函数(例如低通滤波器)不支持的处理。
答案 0 :(得分:2)
您可以使用 GROUPED_AGG
类型的 Pandas UDF。它从 Spark 接收列作为 Pandas 系列,以便您可以在列上调用 Series.mean
。
import pyspark.sql.functions as F
@F.pandas_udf('float', F.PandasUDFType.GROUPED_AGG)
def avg_udf(s):
return s.mean()
df2 = df.groupBy('id').agg(avg_udf('value'))
df2.show()
+---+--------------+
| id|avg_udf(value)|
+---+--------------+
| 1| 1.5|
| 2| 3.5|
+---+--------------+
也可以注册它以在 SQL 中使用:
df.createTempView('df')
spark.udf.register('avg_udf', avg_udf)
df2 = spark.sql("select id, avg_udf(value) from df group by id")
df2.show()
+---+--------------+
| id|avg_udf(value)|
+---+--------------+
| 1| 1.5|
| 2| 3.5|
+---+--------------+
答案 1 :(得分:2)
可以使用 Pandas UDF,其定义与 Spark 3.0
和 Python 3.6+
兼容。有关详细信息,请参阅 issue 和 documentation。
在 Spark SQL 中的完整实现:
import pandas as pd
from pyspark.sql import SparkSession
from pyspark.sql.functions import pandas_udf
from pyspark.sql.types import DoubleType
spark = SparkSession.builder.getOrCreate()
df = spark.createDataFrame(
pd.DataFrame({'id': [1, 1, 2, 2], 'value': [1, 2, 3, 4]}))
df.createTempView('df')
@pandas_udf(DoubleType())
def avg_udf(s: pd.Series) -> float:
return s.mean()
spark.udf.register('avg_udf', avg_udf)
rv = spark.sql('SELECT id, avg_udf(value) FROM df GROUP BY id').toPandas()
带返回值
In [2]: rv
Out[2]:
id avg_udf(value)
0 1 1.5
1 2 3.5