Pandas PySpark SQL中的用户定义聚合函数

Pandas PySpark SQL中的用户定义聚合函数,pandas,apache-spark,pyspark,apache-spark-sql,user-defined-functions,Pandas,Apache Spark,Pyspark,Apache Spark Sql,User Defined Functions,如何在pysparksql中实现用户定义的聚合函数(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.createTe

如何在pysparksql中实现用户定义的聚合函数(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聚合函数(例如低通过滤器)不支持的处理。

您可以将UDF与
GROUPED\u AGG
类型一起使用。它以熊猫系列的形式从Spark接收列,因此您可以在列上调用
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|
+---+--------------+

如果定义与
Spark 3.0
Python 3.6+
兼容,则可以使用熊猫UDF。有关详细信息,请参阅和

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

这回答了你的问题吗?否,因为自Spark 3.0以来,熊猫自定义项的定义发生了变化,所以问题完全相同。spark 3中除了使用python类型提示外没有任何更改…您提供的解决方案对spark 3.0之前的版本有效,请参阅。熊猫UDF的定义已从使用Python 3.6+的Spark 3.0更改。这是在Python3.6+和Spark 3.0+中触发的特定用户警告
,最好为pandas UDF指定类型提示,而不是指定pandas UDF类型,该类型将在未来版本中被弃用。有关更多详细信息,请参见SPARK-28264
我想你的意思是
FloatType
,因为签名使用了
float
,但在其他方面,这是对我的回答的一个很好的改进:)如果你想避免不推荐的功能,我建议你使用
SparkSession
而不是(long)-不推荐使用的
SQLContext
SparkSession
是更好的选择,感谢您指出:)关于
FloatType
vs
DoubleType
,两者都有效,但我认为后者是正确的实现,因为它与
float
一样具有双重精度。我们必须以不同的格式指定两次返回值类型,这似乎是不和谐的。有人知道这背后的原因吗?我不知道,但您可以使用字符串
'double'
,这样可以节省导入和一些键入。。。