我试图从pandas_udf返回一个特定的结构。它在一个集群上工作但在另一个集群上失败。 我尝试在组上运行udf,这要求返回类型为数据框。
from pyspark.sql.functions import pandas_udf
import pandas as pd
import numpy as np
from pyspark.sql.types import *
schema = StructType([
StructField("Distance", FloatType()),
StructField("CarId", IntegerType())
])
def haversine(lon1, lat1, lon2, lat2):
#Calculate distance, return scalar
return 3.5 # Removed logic to facilitate reading
@pandas_udf(schema)
def totalDistance(oneCar):
dist = haversine(oneCar.Longtitude.shift(1),
oneCar.Latitude.shift(1),
oneCar.loc[1:, 'Longitude'],
oneCar.loc[1:, 'Latitude'])
return pd.DataFrame({"CarId":oneCar['CarId'].iloc[0],"Distance":np.sum(dist)},index = [0])
## Calculate the overall distance made by each car
distancePerCar= df.groupBy('CarId').apply(totalDistance)
这是我得到的例外:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
C:\opt\spark\spark-2.3.0-bin-hadoop2.7\python\pyspark\sql\udf.py in returnType(self)
114 try:
--> 115 to_arrow_type(self._returnType_placeholder)
116 except TypeError:
C:\opt\spark\spark-2.3.0-bin-hadoop2.7\python\pyspark\sql\types.py in to_arrow_type(dt)
1641 else:
-> 1642 raise TypeError("Unsupported type in conversion to Arrow: " + str(dt))
1643 return arrow_type
TypeError: Unsupported type in conversion to Arrow: StructType(List(StructField(CarId,IntegerType,true),StructField(Distance,FloatType,true)))
During handling of the above exception, another exception occurred:
NotImplementedError Traceback (most recent call last)
<ipython-input-35-4f2194cfb998> in <module>()
18 km = 6367 * c
19 return km
---> 20 @pandas_udf("CarId: int, Distance: float")
21 def totalDistance(oneUser):
22 dist = haversine(oneUser.Longtitude.shift(1), oneUser.Latitude.shift(1),
C:\opt\spark\spark-2.3.0-bin-hadoop2.7\python\pyspark\sql\udf.py in _create_udf(f, returnType, evalType)
62 udf_obj = UserDefinedFunction(
63 f, returnType=returnType, name=None, evalType=evalType, deterministic=True)
---> 64 return udf_obj._wrapped()
65
66
C:\opt\spark\spark-2.3.0-bin-hadoop2.7\python\pyspark\sql\udf.py in _wrapped(self)
184
185 wrapper.func = self.func
--> 186 wrapper.returnType = self.returnType
187 wrapper.evalType = self.evalType
188 wrapper.deterministic = self.deterministic
C:\opt\spark\spark-2.3.0-bin-hadoop2.7\python\pyspark\sql\udf.py in returnType(self)
117 raise NotImplementedError(
118 "Invalid returnType with scalar Pandas UDFs: %s is "
--> 119 "not supported" % str(self._returnType_placeholder))
120 elif self.evalType == PythonEvalType.SQL_GROUPED_MAP_PANDAS_UDF:
121 if isinstance(self._returnType_placeholder, StructType):
NotImplementedError: Invalid returnType with scalar Pandas UDFs: StructType(List(StructField(CarId,IntegerType,true),StructField(Distance,FloatType,true))) is not supported
我还尝试将架构更改为
@pandas_udf("<CarId:int,Distance:float>")
和
@pandas_udf("CarId:int,Distance:float")
但得到同样的例外。我怀疑它与我的pyarrow版本有关,它与我的pyspark版本不兼容。
任何帮助将不胜感激。谢谢!
答案 0 :(得分:2)
如错误消息中所述(“带有标量熊猫UDF的无效的returnType” ),您正在尝试创建SCALAR向量化的熊猫UDF,但使用的是StructType模式并返回熊猫DataFrame。 / p>
您应该将函数声明为GROUPED MAP pandas UDF,即:
@pandas_udf(schema, PandasUDFType.GROUPED_MAP)
标量和分组矢量化UDF之间的差异在pyspark文档http://spark.apache.org/docs/latest/api/python/pyspark.sql.html#pyspark.sql.functions.pandas_udf中进行了解释。
标量UDF定义了一个转换:一个或多个pandas.Series->一个pandas.Series。 returnType应该是原始数据类型,例如DoubleType()。返回的pandas.Series的长度必须与输入的pandas.Series相同。
总而言之,标量熊猫UDF一次处理一列(pandas系列),与传统的UDF一次处理一个行元素相比,其性能更高。请注意,性能的提高归功于使用PyArrow进行高效的python序列化。
分组地图UDF定义了转换:pandas.DataFrame-> pandas.DataFrame returnType应该是一个StructType,用于描述返回的pandas.DataFrame的架构。返回的pandas.DataFrame的长度可以是任意的,并且必须对列进行索引,以使其位置与架构中的相应字段匹配。
分组的熊猫UDF一次处理多个行和列(使用pandas DataFrame,不要与Spark DataFrame混淆),并且对多变量操作非常有用且高效(特别是在使用本地python数值分析和计算机时)学习numpy,scipy,scikit-learn等库。在这种情况下,输出是具有多列的单行DataFrame。
请注意,我没有检查代码的内部逻辑,仅检查了方法。