Scala 使用Spark ML';多列上的OneHotEncoder

Scala 使用Spark ML';多列上的OneHotEncoder,scala,apache-spark,apache-spark-ml,Scala,Apache Spark,Apache Spark Ml,我已经能够创建一个管道,允许我一次对多个字符串列进行索引,但我无法对它们进行编码,因为与索引不同,编码器不是估计器,所以我从不调用fit 据报道 OneHotEncoder对象没有fit方法,因此将其与索引器放在同一管道中将无法工作-当我在管道上调用fit时,它会抛出一个错误。我也不能在我用管道级数组制作的管道上调用transform,one\u hot\u编码器 我还没有找到一个好的解决方案来使用OneHotEncoder,而不为我想要编码的所有列单独创建和调用转换本身的转换Spark>=3.

我已经能够创建一个管道,允许我一次对多个字符串列进行索引,但我无法对它们进行编码,因为与索引不同,编码器不是估计器,所以我从不调用fit 据报道

OneHotEncoder对象没有fit方法,因此将其与索引器放在同一管道中将无法工作-当我在管道上调用fit时,它会抛出一个错误。我也不能在我用管道级数组制作的管道上调用transform,
one\u hot\u编码器


我还没有找到一个好的解决方案来使用OneHotEncoder,而不为我想要编码的所有列单独创建和调用转换本身的转换

Spark>=3.0

在Spark 3.0中,
OneHotEncoderRestimator
已重命名为
OneHotEncoder

import org.apache.spark.ml.feature.{OneHotEncoder, OneHotEncoderModel}

val encoder = new OneHotEncoder()
  .setInputCols(indexColumns)
  .setOutputCols(indexColumns map (name => s"${name}_vec"))
火花>=2.3

Spark 2.3引入了新的类OneHotEncoderRestimator,
OneHotEncoderModel
,即使在管道外部使用,也需要安装,并同时在多个列上运行

import org.apache.spark.ml.feature.{OneHotEncoderEstimator, OneHotEncoderModel}

val encoder = new OneHotEncoderEstimator()
  .setInputCols(indexColumns)
  .setOutputCols(indexColumns map (name => s"${name}_vec"))


encoder.fit(df_indexed).transform(df_indexed)
火花<2.3

即使您使用的变压器不需要安装,您也必须使用
fit
方法来创建可用于转换数据的
PipelineModel

one_hot_pipeline.fit(df_indexed).transform(df_indexed)
在旁注中,您可以将索引和编码组合到单个
管道中:

val pipeline = new Pipeline()
  .setStages(index_transformers ++ one_hot_encoders)

val model = pipeline.fit(df)
model.transform(df)
编辑


您看到的错误意味着您的一列包含空的
字符串
。它被索引器接受,但不能用于编码。根据您的要求,您可以删除这些标签或使用虚拟标签。不幸的是,在问题解决之前,您不能使用
NULLs

谢谢-我在这里更新了问题。我尝试在管道上调用fit,但我认为我可能设置错误。此外,可能我不完全理解这里的编程范例/当事情实际运行时,但我没有将索引和编码器操作放在同一管道中的原因是,在索引器上调用transform之前,我传递到编码器实例中的列不存在。关于错误,请检查编辑。只要顺序反映依赖关系图(索引器在编码器之前),组合管道就可以正常工作。从SPARK-11569的描述来看,它似乎只适用于PySpark,而不适用于Scala API。带有一列字符串。您是否必须运行
StringIndexer()
以及
OneHotEncoderEstimator()
?或者你可以直接运行后者吗?
val pipeline = new Pipeline()
  .setStages(index_transformers ++ one_hot_encoders)

val model = pipeline.fit(df)
model.transform(df)