CrossValidator не поддерживает VectorUDT как метку в спарк-мл - PullRequest
0 голосов
/ 30 мая 2018

У меня проблема с ml.crossvalidator в scala spark при использовании одного горячего энкодера.

это мой код

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 голосов
/ 30 мая 2018

На самом деле нет необходимости использовать 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 aka категоричны .

Вы также можете заметить, что в атрибуте столбца у вас есть список категорий.

Подробнее об этом в моем другом ответе о Как обрабатывать категориальные функции с помощью spark-мл?

Относительно подготовка данных и метаданные с 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,0.Пожалуйста, используйте OneHotEncoderEstimator вместо.

...