CrossValidator不支持VectorUDT作为spark-ml中的标签

时间:2018-05-30 07:26:13

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

使用一个热编码器时,scala spark中的ml.crossvalidator出现问题。

这是我的代码

val tokenizer = new Tokenizer().
                    setInputCol("subjects").
                    setOutputCol("subject")

//CountVectorizer / TF
val countVectorizer = new CountVectorizer().
                        setInputCol("subject").
                        setOutputCol("features")

// convert string into numerical values
val labelIndexer = new StringIndexer().
                        setInputCol("labelss").
                        setOutputCol("labelsss")

// convert numerical to one hot encoder
val labelEncoder = new OneHotEncoder().
                   setInputCol("labelsss").
                   setOutputCol("label")

val logisticRegression = new LogisticRegression()

val pipeline = new Pipeline().setStages(Array(tokenizer,countVectorizer,labelIndexer,labelEncoder,logisticRegression))

并给我一个像这样的错误

cv: org.apache.spark.ml.tuning.CrossValidator = cv_8cc1ae985e39
java.lang.IllegalArgumentException: requirement failed: Column label must be of type NumericType but was actually of type org.apache.spark.ml.linalg.VectorUDT@3bfc3ba7.

我不知道,如何解决它。

我需要一个热门编码器因为我的标签是绝对的。

感谢您帮助我:)

1 个答案:

答案 0 :(得分:3)

实际上不需要将OneHotEncoder / OneHotEncoderEstimator用于标签(目标变量),而您实际上不应该这样做。这将创建一个向量(type org.apache.spark.ml.linalg.VectorUDT)。

StringIndexer足以定义您的标签是分类的。

让我们在一个小例子中检查:

val df = Seq((0, "a"),(1, "b"),(2, "c"),(3, "a"),(4, "a"),(5, "c")).toDF("category", "text")
// df: org.apache.spark.sql.DataFrame = [category: int, text: string]

val indexer = new StringIndexer().setInputCol("category").setOutputCol("categoryIndex").fit(df)
// indexer: org.apache.spark.ml.feature.StringIndexerModel = strIdx_cf691c087e1d

val indexed = indexer.transform(df)
// indexed: org.apache.spark.sql.DataFrame = [category: int, text: string ... 1 more field]

indexed.schema.map(_.metadata).foreach(println)
// {}
// {}
// {"ml_attr":{"vals":["4","5","1","0","2","3"],"type":"nominal","name":"categoryIndex"}}

正如您所注意到的,StringIndexer实际上将元数据附加到该列(categoryIndex)并将其标记为nominal a.k.a 分类

您还可以注意到,在列的属性中,您有类别列表。

关于How to handle categorical features with spark-ml?

的其他答案中的更多内容

关于使用 spark-ml 数据准备元数据,我强烈建议您阅读以下条目:

https://github.com/awesome-spark/spark-gotchas/blob/5ad4c399ffd2821875f608be8aff9f1338478444/06_data_preparation.md

免责声明:我是该链接中条目的共同作者。

注意:(摘自文档)

  

因为现有的OneHotEncoder是无状态转换器,所以它不适用于类别数量可能与训练数据不同的新数据。为了解决这个问题,我们创建了一个新的OneHotEncoderEstimator,在拟合时产生OneHotEncoderModel。有关详细信息,请参阅SPARK-13030

     

OneHotEncoder已在 2.3.0 已弃用,并将在3.0.0中删除。请改用OneHotEncoderEstimator