Spark自定义估算器访问Param [T]

时间:2016-11-28 15:13:29

标签: scala apache-spark apache-spark-sql apache-spark-ml

我正在建立一个火花的自定义估算器。不幸的是,我如何访问估算器的Param[T]默认参数似乎有些不对劲。以下是将TransformerEstimator进行比较的最小示例。可以访问相同参数的Estimator

trait PreprocessingParam2s extends Params {
  final val isInList = new Param[Array[String]](this, "isInList", "list of isInList items")
}

被称为

new ExampleEstimator().setIsInList(Array("def", "ABC")).fit(dates).transform(dates).show

为了执行

dataset
      .withColumn("isInList", when('ISO isin ($(isInList): _*), 1).otherwise(0))

但与工作正常的Transformer不同,Estimator失败,java.util.NoSuchElementException: Failed to find a default value for isInList

https://gist.github.com/geoHeil/218683c6b0f91bc76f71cb652cd746b8https://github.com/geoHeil/sparkEstimatorProblem(包括build.sbt文件,以便更轻松地重现问题)

这里有什么问题?

修改

我正在使用spark 2.0.2。

正如@ t-gawęda所指出的那样,在设置默认参数时可以修复错误。但是,当我调用新的ExampleEstimator().setIsInList(Array("def", "ABC"))时,这不应该是必要的。那么为什么参数没有设置?

如果我设置默认参数,则将它们用作后备。但这不是我想要达到的语义。而不是正确的输出(Transformer

+----------+---+--------+
|     dates|ISO|isInList|
+----------+---+--------+
|2016-01-01|ABC|       1|
|2016-01-02|ABC|       1|
|2016-01-03|POL|       0|
|2016-01-04|ABC|       1|
|2016-01-05|POL|       0|
|2016-01-06|ABC|       1|
|2016-01-07|POL|       0|
|2016-01-08|ABC|       1|
|2016-01-09|def|       1|
|2016-01-10|ABC|       1|
+----------+---+--------+

+--------+                                                                      
|isInList|
+--------+
|       1|
|       0|
+--------+

我得到了

+----------+---+--------+
|     dates|ISO|isInList|
+----------+---+--------+
|2016-01-01|ABC|       0|
|2016-01-02|ABC|       0|
|2016-01-03|POL|       0|
|2016-01-04|ABC|       0|
|2016-01-05|POL|       0|
|2016-01-06|ABC|       0|
|2016-01-07|POL|       0|
|2016-01-08|ABC|       0|
|2016-01-09|def|       0|
|2016-01-10|ABC|       0|
+----------+---+--------+

+--------+
|isInList|
+--------+
|       0|
+--------+

明显错误的地方,例如仅使用默认参数。我存储参数的方法有什么问题? 请参阅设置默认参数的工作示例https://github.com/geoHeil/sparkEstimatorProblem

1 个答案:

答案 0 :(得分:3)

尝试在参数中添加getter和setDefault:

trait PreprocessingParam2s extends Params {
  final val isInList = new Param[Array[String]](this, "isInList", "list of isInList items")

 setDefault(isInList, /* here put default value */)

  /** @group getParam */
  final def getIsInList: Array[String] = $(isInList)
}

为什么?

看看如何创建params地图:

lazy val params: Array[Param[_]] = {
    val methods = this.getClass.getMethods
    methods.filter { m =>
        Modifier.isPublic(m.getModifiers) &&
          classOf[Param[_]].isAssignableFrom(m.getReturnType) &&
          m.getParameterTypes.isEmpty
      }.sortBy(_.getName)
      .map(m => m.invoke(this).asInstanceOf[Param[_]])
}

Spark会扫描类中的所有方法,并使用以下方法搜索方法:

  • public modifier
  • 无参数
  • 返回类型是Param的子类型

Spark启动这些方法并将值放入参数map中。当您读取参数值时,Spark会查看此映射,而不是执行getter

完整代码为here 说明:在模型中,您必须具有:

def setIsInList(value : Array[String]): this.type = {
    set(isInList, value)
    this
  }

并且在估算器的拟合方法中:

override def fit(dataset: Dataset[_]): ExampleTransModel = new ExampleTransModel(uid, 1.0).setIsInList($(this.isInList))

创建模型后,您没有将参数值复制到模型对象 - 这就是评估模型时它始终为空的原因