首页 > 解决方案 > 我可以在 PMML(从 Spark 导出)中使用没有 One-Hot-Encoding 的 StringIndexer 吗?

问题描述

我正在尝试采用功能齐全的 SparkML 管道(出于兼容性原因,Scala、Spark 2.1.1)并将其转换为 PMML 以实现互操作性和存储目的。

目前,管道具有以下形式:Array(StringIndexer,StringIndexer,VectorAssembler,VectorIndexer)。我已经尝试过标准的 org.jpmml.sparkml.PMMLBuilder,它在我已经为数据库中的字符串编制索引的情况下工作得非常好。(我知道这些列中有多少不同的字符串,我完全确定它们会保持分类。)我计划在决策树和其他一些基于树的方法中使用它们,SparkML 有对树中的分类变量进行可爱的处理,这使得 one-hot-encoding 不太理想。

val strCols = Array("stringCol1","stringCol2")

val strIndexers = strCols.map(c => new StringIndexer().setInputCol(c).setOutputCol(c+"_Indexed"))

val collist = df.columns.diff(strCols) ++ strCols.map(c => c+"_Indexed")

val vectorAssembler = new VectorAssembler() 
    .setInputCols(collist)
    .setOutputCol("rawFeatures")

val vectorIndexer = new VectorIndexer().setInputCol("rawFeatures").setOutputCol("features").setMaxCategories(35)

val pipeintro = new Pipeline().setStages(strIndexers :+ vectorAssembler :+ vectorIndexer)
val pipeIntro = pipeintro.fit(df)

val pmmlBuilder = new org.jpmml.sparkml.PMMLBuilder(df.schema, pipeIntro).buildFile(new File("out.pmml"))

我希望代码完成运行并输出适当的 PMML,但我得到的是:

java.lang.IllegalArgumentException: Field stringCol1 has valid values [MT, IP, OB, GA, ED, OP]
  at org.jpmml.converter.PMMLEncoder.toCategorical(PMMLEncoder.java:209)
  at org.jpmml.sparkml.feature.VectorIndexerModelConverter.encodeFeatures(VectorIndexerModelConverter.java:80)
  at org.jpmml.sparkml.FeatureConverter.registerFeatures(FeatureConverter.java:47)
  at org.jpmml.sparkml.PMMLBuilder.build(PMMLBuilder.java:114)
  at org.jpmml.sparkml.PMMLBuilder.buildFile(PMMLBuilder.java:292)

我检查了空值;没有,也没有其他无效的值。有一些迹象表明,StringIndexers 在放入 VectorAssembler 之前应该是单热编码的,但这对于这个特定的管道来说不是最理想的,因为它旨在馈送到 SparkML 定义的树中,它可以很好地处理多值分类列. 该指南是否被硬编码到 PMML 或 Spark-PMML 编码器中?我还缺少其他一些错误吗?

标签: apache-sparkapache-spark-mlpmml

解决方案


这个特殊的例外是关于冲突的“stringCol1”定义 - 它的值空间已由StringIndexer([MT, IP, OB, GA, ED, OP]) 定义,现在VectorIndexer正试图用不同的值空间重新定义它。其中一项尝试是错误的。

可能是 JPMML-SparkML 库或您的脚本的错误。也许StringIndexerModel根本不应该是 VectorIndexed 的输出?


推荐阅读