使用一种热编码和向量汇编器与向量索引器解决分类特征

时间:2019-01-16 17:55:50

标签: scala apache-spark machine-learning categorical-data apache-spark-ml

说我在数据框中具有分类功能。为了在数据帧上执行ML,我使用OneHotEncoderEstimator()对分类列进行了一次热编码,然后使用VectorAssembler()将所有功能组合到一个列中。在阅读Spark docs时,我已经看到使用VectorIndexer()在特征向量列中为分类特征建立索引。如果我在公式化特征向量列之前已经对分类列执行了一种热编码,那么在其上应用VectorIndexer()有什么意义。

1 个答案:

答案 0 :(得分:1)

OneHotEncoder(Estimator)VectorIndexer是完全不同的野兽,不能互换。主要在下游流程使用线性模型(it can be also used with Naive Bayes)时使用OneHotEncoder(Estimator)

让我们考虑一个简单的Dataset

val df = Seq(1.0, 2.0, 3.0).toDF

和一个Pipeline

import org.apache.spark.ml.Pipeline
import org.apache.spark.ml.feature._

val m1 = new Pipeline().setStages(Array(
  new OneHotEncoderEstimator()
   .setInputCols(Array("value")).setOutputCols(Array("features"))
)).fit(df)

如果将这样的模型应用于我们的数据,它将为one-hot-encoded(取决于配置OneHotEncoderEstimator支持单次热编码和伪编码)-换句话说,每个级别(不包括引用)表示为单独的二进制列:

m1.transform(df).schema("features").metadata
 org.apache.spark.sql.types.Metadata = {"ml_attr":{"attrs":{"binary":[{"idx":0,"name":"0"},{"idx":1,"name":"1"},{"idx":2,"name":"2"}]},"num_attrs":3}}

请注意,这种表示方式与本地处理分类特征的算法一起使用时效率低下并且不切实际。

相反,VectorIndexer仅分析数据,并相应地调整元数据

val m2 = new Pipeline().setStages(Array(
  new VectorAssembler().setInputCols(Array("value")).setOutputCol("raw"),
  new VectorIndexer().setInputCol("raw").setOutputCol("features")
)).fit(df)

m2.transform(df).schema("features").metadata
org.apache.spark.sql.types.Metadata = {"ml_attr":{"attrs":{"nominal":[{"ord":false,"vals":["1.0","2.0","3.0"],"idx":0,"name":"value"}]},"num_attrs":1}}

换句话说,它或多或少地等同于StringIndexer的向量化变体(您可以使用一组StringIndexers后跟{{ 1}})。

这类功能是unsuitable for linear models,但对于决策树和树集成来说是有效的输入。

总结-实际上,VectorAssemblerOneHotEncoder(Esitmator)是互斥的,应该使用哪个选择取决于下游过程。