pyspark pandas_udf

参考:
pyspark 官网
使用Pandas_UDF快速改造Pandas代码
PySpark pandas udf
Spark 官网

Apache Arrow

Apache Arrow 是 Apache 基金会全新孵化的一个顶级项目。一个跨平台的在内存中以列式存储的数据层,它设计的目的在于作为一个跨平台的数据层,来加快大数据分析项目的运行速度。
Pandas 建立在ApacheArrow 之上,带来了低开销,高性能的 udf.

pandas_udf

在过去的几年中,python 正在成为数据分析师的默认语言。一些类似 pandas,numpy,statsmodel,scikit-learn 被大量使用,逐渐成为主流的工具包。同时,spark 也成为了大数据处理的标准,为了让数据分析师能够使用 spark ,Spark在 0.7 版本增加了 python api,也支持了 udf (user-defined functions)。
这些 udf 对每条记录都会操作一次,同时数据需要在 JVM 和 Python 中传输,因此有了额外的序列化和调用开销。因此可以用 Java 和 Scala 中定义 UDF,然后在 python 中调用它们。
1.循环执行 转化为 pandas 向量化计算。
2.python 和 JVM 使用同一种数据结构,避免了序列化的开销

配置

安装pyarrow
spark df 与 pandas df 相互转化性能优化,需要开启配置,默认为关闭。

spark.sql.execution.arrow.enabled true

spark=SparkSession.builder.\
        master(url)\
        .appName(name).\
         config("spark.sql.execution.arrow.enabled",'true')\
        getOrCreate()

性能对比:
spark.sql.execution.arrow.enabled 开启前后对比程序
eg:

pdf = pd.DataFrame(np.random.rand(100000, 3))
%time df = spark.createDataFrame(pdf)
%time result_pdf = df.select("*").toPandas()

pandas_udf介绍

pandas udf 的入参和返回值类型都为 pandas.Series
pyspark.sql.functions.pandas_udf(f=None, returnType=None, functionType=None)
参数说明:
f – user-defined function. A python function if used as a standalone function
returnType – the return type of the user-defined function. The value can be either a pyspark.sql.types.DataType object or a DDL-formatted type string.
functionType – an enum value in pyspark.sql.functions.PandasUDFType. Default: SCALAR.

Pandas_UDF是在PySpark2.3中新引入的API,由Spark使用Arrow传输数据,使用Pandas处理数据。Pandas_UDF是使用关键字pandas_udf作为装饰器或包装函数来定义的,不需要额外的配置。目前,有两种类型的Pandas_UDF,分别是Scalar(标量映射)和Grouped Map(分组映射)。

  • Scalar
    Scalar Pandas UDF用于向量化标量操作。常常与select和withColumn等函数一起使用。其中调用的Python函数需要使用pandas.Series作为输入并返回一个具有相同长度的pandas.Series。具体执行流程是,Spark将列分成批,并将每个批作为数据的子集进行函数的调用,进而执行panda UDF,最后将结果连接在一起
    例子:
from pyspark.sql.functions import pandas_udf,PandasUDFType
from pyspark.sql.types import IntegerType,StringType
slen=pandas_udf(lambda s:s.str.len(),IntegerType())
@pandas_udf(StringType())
def to_upper(s):
   return s.str.upper()

@pandas_udf(IntegerType(),PandasUDFType.SCALAR)
def add_one(x):
   return x+1

df = spark.createDataFrame([(1, "John Doe", 21)], ("id", "name", "age"))
df.select(slen("name").alias("slen(name)"), to_upper("name"), add_one("age")).show()
df.withColumn('slen(name)',slen("name")).show()

结果:
pyspark pandas_udf_第1张图片

  • Grouped Map
    Grouped map(分组映射)panda udf与groupBy().apply()一起使用,后者实现了“split-apply-combine”模式。“split-apply-combine”包括三个步骤:

使用DataFrame.groupBy将数据分成多个组。
对每个分组应用一个函数。函数的输入和输出都是pandas.DataFrame。输入数据包含每个组的所有行和列。
将结果合并到一个新的DataFrame中。
要使**

用groupBy().apply(),

**需要定义以下内容:

定义每个分组的Python计算函数,这里可以使用pandas包或者Python自带方法。
一个StructType对象或字符串,它定义输出DataFrame的格式,包括输出特征以及特征类型。
需要注意的是,StructType对象中的Dataframe特征顺序需要与分组中的Python计算函数返回特征顺序保持一致。

此外,在应用该函数之前,分组中的所有数据都会加载到内存,这可能导致内存不足抛出异常。
例子

from pyspark.sql.functions import pandas_udf, PandasUDFType
df = spark.createDataFrame(
    [(1, 1.0), (1, 2.0), (2, 3.0), (2, 5.0), (2, 10.0)],("id", "v"))
@pandas_udf("id long, v double", PandasUDFType.GROUPED_MAP) 
def normalize(pdf):
     v = pdf.v
     return pdf.assign(v=(v - v.mean()) / v.std())

df.groupby("id").apply(normalize).show()

结果:
pyspark pandas_udf_第2张图片

  • GROUPED_AGG
    Grouped aggregate Panda UDF类似于Spark聚合函数。Grouped aggregate Panda UDF常常与groupBy().agg()和pyspark.sql.window一起使用。它定义了来自一个或多个的聚合。级数到标量值,其中每个pandas.Series表示组或窗口中的一列。

需要注意的是,这种类型的UDF不支持部分聚合,组或窗口的所有数据都将加载到内存中。此外,目前只支持Grouped aggregate Pandas UDFs的无界窗口。
eg

from pyspark.sql.functions import pandas_udf, PandasUDFType
df = spark.createDataFrame(
    [(1, 1.0), (1, 2.0), (2, 3.0), (2, 5.0), (2, 10.0)],("id", "v"))
@pandas_udf("double", PandasUDFType.GROUPED_AGG)  
def mean_udf(v):
     return v.mean()
df.groupby("id").agg(mean_udf(df['v'])).show() 

结果:
pyspark pandas_udf_第3张图片

你可能感兴趣的:(pyspark)