【问题标题】:Implicit schema for pandas_udf in PySpark?PySpark 中 pandas_udf 的隐式模式?
【发布时间】:2023-03-04 16:23:02
【问题描述】:

This answer 很好地解释了如何使用 pyspark 的 groupby 和 pandas_udf 进行自定义聚合。但是,我不可能像示例的这一部分所示手动声明我的架构

from pyspark.sql.types import *

schema = StructType([
    StructField("key", StringType()),
    StructField("avg_min", DoubleType())
])

因为我将返回 100 多列自动生成的名称。有没有办法告诉 PySpark 只是隐含地使用我的函数返回的 Schema 并假设它对于所有工作节点都是相同的?这个模式也会在运行过程中发生变化,因为我将不得不使用我想要使用的预测器,所以一个用于模式生成的自动化过程可能是一个选项......

【问题讨论】:

标签: python apache-spark pyspark user-defined-functions


【解决方案1】:

稍微修改@Thomas 回答我做了以下。由于df.types 返回的是元组列表(至少在最新的pandas 版本中)而不是字典,所以我将str(dfp.dtypes[key]) 替换为dict(df.dtypes)[key]

def udf_schema_from_pandas(df):
  column_types  = [StructField(key, mapping[dict(df.dtypes)[key]]()) for key in df.columns]
  schema = StructType(column_types)
  return schema

【讨论】:

    【解决方案2】:

    基于Sanxofons comment,,我对如何自己实现这一点有了一个想法:

    from pyspark.sql.types import *
    
    mapping = {"float64": DoubleType,
               "object":StringType,
               "int64":IntegerType} # Incomplete - extend with your types.
    
    def createUDFSchemaFromPandas(dfp):
      column_types  = [StructField(key, mapping[str(dfp.dtypes[key])]()) for key in dfp.columns]
      schema = StructType(column_types)
      return schema
    

    我所做的是获取一个示例 pandas df,将其传递给函数,然后查看返回什么:

    dfp = df_total.limit(100).toPandas()
    df_return = my_UDF_function(dfp)
    schema = createUDFSchemaFromPandas(df_return)
    

    这似乎对我有用。问题在于它是一种递归(需要定义函数来获取模式,将模式定义为 udf)。我通过创建一个简单地传递数据帧的“包装器”UDF 解决了这个问题。

    【讨论】:

      【解决方案3】:

      不幸的是,没有这样的选择。在评估任何组件之前,必须静态地知道模式,因此任何基于实际数据的形式推断都根本不在讨论范围内。

      如果内部流程以某种方式基于代码生成,那么您最好的选择是集成逻辑和模式生成。例如

      def describe(cols, fun):
          schema = StructType([StructField(c, DoubleType()) for c in cols])
          @pandas_udf(schema, PandasUDFType, PandasUDFType.GROUPED_MAP)
          def _(df):
              return df[cols].agg([fun])
          return _
      
      df = spark.createDataFrame([(1, 2.0, 1.0, 3.0), (1, 4.0, 2.0, 5.0)], ("id", "x", "y", "z"))
      
      df.groupBy("id").apply(describe(["x"], "mean")).show()                                         
      # +---+                                                                           
      # |  x|
      # +---+
      # |3.0|
      #+---+
      
      
      df.groupBy("id").apply(describe(["x", "y"], "mean")).show()                                    
      # +---+---+                                                                       
      # |  x|  y|
      # +---+---+
      # |3.0|1.5|
      # +---+---+
      

      【讨论】:

      • 这并不是我真正需要的 - 我的输出架构与我的输入架构不同。
      猜你喜欢
      • 2023-03-25
      • 2018-12-28
      • 1970-01-01
      • 2020-05-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-02
      • 1970-01-01
      相关资源
      最近更新 更多