【问题标题】:CrossValidator does not support VectorUDT as label in spark-mlCrossValidator 不支持 VectorUDT 作为 spark-ml 中的标签
【发布时间】:2018-11-09 17:59:05
【问题描述】:

我在使用一个热编码器时遇到了 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.

我不知道如何解决它。

我需要一个热编码器,因为我的标签是分类的。

谢谢你帮助我:)

【问题讨论】:

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


    【解决方案1】:

    实际上没有必要将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 又名 分类

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

    在我关于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

    【讨论】:

    • 感谢您的帮助。是的 stringIndexer 就足够了。但是我的教授说,如果我们将数字用于分类仍然有缺点。 a , b, c = 0,1,2 。但这意味着 c>b 。所以我们需要一个热编码器。但是在教授 MLP 时说。 LogReg 也需要 oneHotEncoder 吗?
    • 我不相信他对标签这么说。逻辑回归有时可以从 OHE 中受益,有时实际上并不需要。特征工程取决于学习任务、数据的性质以及最重要的模型性能。 OHE 与 RF 的行为方式与 LR 不同。 @AliHelmutBaltschun
    猜你喜欢
    • 2022-10-22
    • 1970-01-01
    • 2022-08-24
    • 2018-12-13
    • 2016-04-13
    • 2017-02-11
    • 1970-01-01
    • 2016-08-03
    相关资源
    最近更新 更多