Apache spark 包含持久性的Spark自定义估计

Apache spark 包含持久性的Spark自定义估计,apache-spark,apache-spark-sql,pipeline,apache-spark-mllib,apache-spark-ml,Apache Spark,Apache Spark Sql,Pipeline,Apache Spark Mllib,Apache Spark Ml,我想为spark开发一个自定义估计器,该估计器还可以处理伟大的管道API的持久性。但正如我们所说的,目前还没有太多的文档 我有一些用spark编写的数据清理代码,希望将其封装在自定义估计器中。包括一些na替换、列删除、过滤和基本特征生成(例如,从出生日期到年龄) transformSchema将使用[MyClass].dataType.asInstanceOf[StructType] 适合仅适合,例如平均年龄为na。替代品 我还不清楚的是: transform在自定义管道模型中,将用于转换

我想为spark开发一个自定义估计器,该估计器还可以处理伟大的管道API的持久性。但正如我们所说的,目前还没有太多的文档

我有一些用spark编写的数据清理代码,希望将其封装在自定义估计器中。包括一些na替换、列删除、过滤和基本特征生成(例如,从出生日期到年龄)

  • transformSchema将使用[MyClass].dataType.asInstanceOf[StructType]
  • 适合仅适合,例如平均年龄为na。替代品
我还不清楚的是:

  • transform
    在自定义管道模型中,将用于转换新数据上的“拟合”估计器。这是正确的吗?如果是,我应该如何将拟合值(例如,平均年龄)从上面转移到模型中

  • 如何处理持久性?我在private spark组件中找到了一些通用的
    loadImpl
    方法,但不确定如何将自己的参数(例如平均年龄)传输到用于序列化的
    MLReader
    /
    MLWriter


如果你能帮我定制一个估计器,那就太好了,尤其是持久性部分。

首先,我相信你混合了两种不同的东西:

  • -表示可
    fit
    -ted的阶段
    Estimator
    fit
    方法获取
    Dataset
    并返回
    Transformer
    (模型)
  • -表示可以转换数据的阶段
当您
拟合
管道
时,它
拟合
所有
估计器
并返回
管道模型
PipelineModel
可以对模型中的所有
Transformer
按顺序调用
transform
数据

我应该如何传递拟合值

这个问题没有单一的答案。通常,您有两种选择:

  • 将拟合模型的参数作为变压器的参数传递
  • 变压器的安装模型制作参数
第一种方法通常由内置的
转换器使用,但是第二种方法在一些简单的情况下应该可以工作

如何处理持久性

  • 如果
    Transformer
    仅由其
    Params
    定义,则可以扩展
    DefaultParamsReadable
  • 如果使用更复杂的参数,则应扩展
    mlwriteable
    ,并实现对数据有意义的
    MLWriter
    。Spark source中有多个示例演示了如何实现数据和元数据的读/写
如果您正在寻找一个易于理解的示例,请查看
CountVectorizer(Model)
其中:

  • 估计器
    变压器
  • 模型词汇,模型
  • 元数据(参数)是一个使用
    DefaultParamsWriter
    /
    DefaultParamsReader
    的文件
  • 自定义实现处理数据(词汇表)和

下面使用的是Scala API,但是如果您真的想

第一件事:

  • 估计器:实现返回变压器的
    .fit()
  • Transformer:实现
    .transform()
    并操作数据帧
  • 序列化/反序列化:尽量使用内置参数并利用简单的
    defaultparamswitable
    trait+伴随对象扩展
    DefaultParamsReadable[T]
    。a、 k.a远离MLReader/MLWriter,保持代码简单
  • 参数传递:使用扩展
    参数的共同特征
    ,并在估计器和模型之间共享它(也称为Transformer)
骨架代码:

// Common Parameters
trait MyCommonParams extends Params {
  final val inputCols: StringArrayParam = // usage: new MyMeanValueStuff().setInputCols(...)
    new StringArrayParam(this, "inputCols", "doc...")
    def setInputCols(value: Array[String]): this.type = set(inputCols, value)
    def getInputCols: Array[String] = $(inputCols)

  final val meanValues: DoubleArrayParam = 
    new DoubleArrayParam(this, "meanValues", "doc...")
    // more setters and getters
}

// Estimator
class MyMeanValueStuff(override val uid: String) extends Estimator[MyMeanValueStuffModel] 
  with DefaultParamsWritable // Enables Serialization of MyCommonParams
  with MyCommonParams {

  override def copy(extra: ParamMap): Estimator[MeanValueFillerModel] = defaultCopy(extra) // deafult
  override def transformSchema(schema: StructType): StructType = schema // no changes
  override def fit(dataset: Dataset[_]): MyMeanValueStuffModel = {
    // your logic here. I can't do all the work for you! ;)
   this.setMeanValues(meanValues)
   copyValues(new MyMeanValueStuffModel(uid + "_model").setParent(this))
  }
}
// Companion object enables deserialization of MyCommonParams
object MyMeanValueStuff extends DefaultParamsReadable[MyMeanValueStuff]

// Model (Transformer)
class MyMeanValueStuffModel(override val uid: String) extends Model[MyMeanValueStuffModel] 
  with DefaultParamsWritable // Enables Serialization of MyCommonParams
  with MyCommonParams {

  override def copy(extra: ParamMap): MyMeanValueStuffModel = defaultCopy(extra) // default
  override def transformSchema(schema: StructType): StructType = schema // no changes
  override def transform(dataset: Dataset[_]): DataFrame = {
      // your logic here: zip inputCols and meanValues, toMap, replace nulls with NA functions
      // you have access to both inputCols and meanValues here!
  }
}
// Companion object enables deserialization of MyCommonParams
object MyMeanValueStuffModel extends DefaultParamsReadable[MyMeanValueStuffModel]
使用上面的代码,您可以序列化/反序列化包含MyMeanValueStuff阶段的管道


想看看估计器的一些真正简单的实现吗!(虽然我的示例实际上更简单…

仅扩展DefaultParamsReadable和DefaultParamsWritable就可以给出java.lang.NoSuchMethodException:read()。示例似乎使用DefaultParamsWriter和DefaultParamsReader,但它们被标记为private[ml],不能在自定义转换器中使用。“我错过什么了吗?”保罗听起来不像你。根据读/写合同阶段,你需要
MLReadable[\u]
/
mlwriteable[\u]
,这需要伴随
MLReader[\u]
/
MLWriter[\u]
来满足他们的
read
write
方法。你知道这方面的一个好例子吗。我能找到的每个示例都涉及DefaultParamsReader和DefaultParamsWriter,它们都是私有的[ml],使我无法访问它们。在你的例子中,我不明白什么?