Apache spark 包含持久性的Spark自定义估计
我想为spark开发一个自定义估计器,该估计器还可以处理伟大的管道API的持久性。但正如我们所说的,目前还没有太多的文档 我有一些用spark编写的数据清理代码,希望将其封装在自定义估计器中。包括一些na替换、列删除、过滤和基本特征生成(例如,从出生日期到年龄)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在自定义管道模型中,将用于转换
- transformSchema将使用[MyClass].dataType.asInstanceOf[StructType]
- 适合仅适合,例如平均年龄为na。替代品
在自定义管道模型中,将用于转换新数据上的“拟合”估计器。这是正确的吗?如果是,我应该如何将拟合值(例如,平均年龄)从上面转移到模型中transform
- 如何处理持久性?我在private spark组件中找到了一些通用的
方法,但不确定如何将自己的参数(例如平均年龄)传输到用于序列化的loadImpl
/MLReader
中MLWriter
如果你能帮我定制一个估计器,那就太好了,尤其是持久性部分。首先,我相信你混合了两种不同的东西:
- -表示可
-ted的阶段fit
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],使我无法访问它们。在你的例子中,我不明白什么?