【问题标题】:Using Spark ML's OneHotEncoder on multiple columns在多列上使用 Spark ML 的 OneHotEncoder
【发布时间】:2016-03-14 00:50:43
【问题描述】:

我已经能够创建一个管道,允许我一次索引多个字符串列,但我在编码它们时遇到了困难,因为与索引不同,编码器不是估计器,所以我从不调用 fit 根据OneHotEncoder example in the docs.

import org.apache.spark.ml.feature.{StringIndexer, VectorAssembler, 

OneHotEncoder}
import org.apache.spark.ml.Pipeline

val data = sqlContext.read.parquet("s3n://map2-test/forecaster/intermediate_data")

val df = data.select("win","bid_price","domain","size", "form_factor").na.drop()


//indexing columns
val stringColumns = Array("domain","size", "form_factor")
val index_transformers: Array[org.apache.spark.ml.PipelineStage] = stringColumns.map(
  cname => new StringIndexer()
    .setInputCol(cname)
    .setOutputCol(s"${cname}_index")
)

// Add the rest of your pipeline like VectorAssembler and algorithm
val index_pipeline = new Pipeline().setStages(index_transformers)
val index_model = index_pipeline.fit(df)
val df_indexed = index_model.transform(df)


//encoding columns
val indexColumns  = df_indexed.columns.filter(x => x contains "index")
val one_hot_encoders: Array[org.apache.spark.ml.PipelineStage] = indexColumns.map(
    cname => new OneHotEncoder()
     .setInputCol(cname)
     .setOutputCol(s"${cname}_vec")
)



val one_hot_pipeline = new Pipeline().setStages(one_hot_encoders)
val df_encoded = one_hot_pipeline.transform(df_indexed)

OneHotEncoder 对象没有 fit 方法,因此将其与索引器放在同一管道中将不起作用 - 当我在管道上调用 fit 时会引发错误。我也不能在使用管道阶段数组one_hot_encoders 制作的管道上调用转换。

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

【问题讨论】:

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


    【解决方案1】:

    Spark >= 3.0

    在 Spark 3.0 中,OneHotEncoderEstimator 已重命名为 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 引入了新的类OneHotEncoderEstimatorOneHotEncoderModel,即使在Pipeline 之外使用也需要拟合,并同时对多个列进行操作。

    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)
    

    火花

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

    one_hot_pipeline.fit(df_indexed).transform(df_indexed)
    

    附带说明,您可以将索引和编码组合成一个 Pipeline

    val pipeline = new Pipeline()
      .setStages(index_transformers ++ one_hot_encoders)
    
    val model = pipeline.fit(df)
    model.transform(df)
    

    编辑

    您看到的错误意味着您的一列包含一个空的String。它被索引器接受,但不能用于编码。根据您的要求,您可以删除这些或使用虚拟标签。很遗憾,在解决 SPARK-11569) 之前,您不能使用 NULLs

    【讨论】:

    • 谢谢 - 我在这里更新了问题。我尝试在管道上调用 fit,但我想我可能设置错了。
    • 另外,也许我不完全理解这里的编程范式/当事情实际运行时,但我没有将索引和编码器操作放入同一个管道的原因是我的列在索引器上调用 transform 之前,传递给编码器实例的参数不存在。
    • 关于您看到的错误,请检查编辑。只要长顺序反映依赖图(索引器在编码器之前),组合管道就可以正常工作。
    • 从 SPARK-11569 的描述来看,它似乎只适用于 PySpark,不适用于 Scala API。
    • 带有一列字符串。你必须同时运行StringIndexer()OneHotEncoderEstimator() 吗?或者你可以只运行后者吗?
    猜你喜欢
    • 2016-07-24
    • 2018-10-21
    • 1970-01-01
    • 2019-07-27
    • 2020-06-10
    • 2019-05-17
    • 2017-08-10
    • 1970-01-01
    • 2017-08-24
    相关资源
    最近更新 更多