2016-01-08 2 views
8

Моя цель - построить классификатор multicalss.Spark, ML, StringIndexer: обработка невидимых меток

Я построил конвейер для извлечения функции и включает в себя в качестве первого шага трансформатор StringIndexer для сопоставления каждого имени класса с меткой, эта метка будет использоваться на этапе обучения классификатора.

В трубопроводе установлен учебный комплект.

Испытательный комплект должен быть обработан установленным трубопроводом для извлечения тех же векторов признаков.

Зная, что мои файлы тестовых наборов имеют одинаковую структуру учебного набора. Возможный сценарий здесь заключается в том, чтобы столкнуться с невидимым именем класса в тестовом наборе, в этом случае StringIndexer не сможет найти метку, и будет создано исключение.

Есть ли решение для этого случая? или как мы можем избежать этого?

ответ

7

Никакой хороший способ сделать это, я боюсь. Либо

  • фильтр из примеров испытаний с неизвестными этикетками перед нанесением StringIndexer
  • или приспосабливать StringIndexer к соединению поезда и тест dataframe, так что вы уверены, все ярлыки есть
  • или преобразовать тестовый пример случай с неизвестной этикеткой с известным лейблом

Вот некоторые примеры кода для выполнения операций над:

// get training labels from original train dataframe 
val trainlabels = traindf.select(colname).distinct.map(_.getString(0)).collect //Array[String] 
// or get labels from a trained StringIndexer model 
val trainlabels = simodel.labels 

// define an UDF on your dataframe that will be used for filtering 
val filterudf = udf { label:String => trainlabels.contains(label)} 

// filter out the bad examples 
val filteredTestdf = testdf.filter(filterudf(testdf(colname))) 

// transform unknown value to some value, say "a" 
val mapudf = udf { label:String => if (trainlabels.contains(label)) label else "a"} 

// add a new column to testdf: 
val transformedTestdf = testdf.withColumn("newcol", mapudf(testdf(colname))) 
+0

Не существует способа предоставить тестовые данные без какой-либо метки вообще, чтобы алгоритм предсказал ее с нуля. В моем случае у меня нет меток ни для одного из моих тестовых данных. См.: Https://stackoverflow.com/questions/44127634/providing-test-data-items-with-empty-labels-in-spark-random-forest-classifier В моем случае мне нужно связать случайные метки для предметы? – suat

+0

Ответ от @queise с использованием искры 2.2 теперь лучший ответ – mrjrdnthms

10

В Spark 1.6 есть способ обойти это.

Вот JIRA: https://issues.apache.org/jira/browse/SPARK-8764

Вот пример:

val categoryIndexerModel = new StringIndexer() 
    .setInputCol("category") 
    .setOutputCol("indexedCategory") 
    .setHandleInvalid("skip") // new method. values are "error" or "skip" 

Я начал использовать это, но в конечном итоге вернуться к 2 пули точки KrisP в об установке этого конкретного оценщик в полном наборе данных.

Вам понадобится это позже в конвейере, когда вы конвертируете IndexToString.

Вот модифицированный пример:

val categoryIndexerModel = new StringIndexer() 
    .setInputCol("category") 
    .setOutputCol("indexedCategory") 
    .fit(itemsDF) // Fit the Estimator and create a Model (Transformer) 

... do some kind of classification ... 

val categoryReverseIndexer = new IndexToString() 
    .setInputCol(classifier.getPredictionCol) 
    .setOutputCol("predictedCategory") 
    .setLabels(categoryIndexerModel.labels) // Use the labels from the Model 
+3

Но что происходит, когда вы пытаетесь применить модель к новым данным? Вы можете обнаружить, что в некоторых столбцах есть новые значения, которые не были в исходных тестах или данных обучения. Я боюсь, что setHandleInvalid («skip») приведет к отбрасыванию всей строки, когда вы действительно просто хотите игнорировать ранее невидимое значение, но все равно используйте другие значения в строке. – user1933178

+0

это означало бы, что новые невидимые данные не относятся к тому же статистическому распределению, что и данные обучения. Это нормально, и на самом деле желательно, чтобы в большинстве приложений НЕ подавалось это ярлык, поскольку он не «выглядит» как любые данные, которые ранее видели в модели. «Похоже» в статистическом смысле, очевидно, пытались сделать «Учимся НЕ запоминать». – Kai

+1

Существует новая опция .setHandleInvalid («держать»), поставляемая с Spark 2.2., Которая добавит новые индексы при работе с новыми данными. По-моему, эта функция будет очень полезна, так как, как мы надеемся, прогностическая модель, которую вы применяете впоследствии, выдает достоверное предсказание, используя все остальные переменные (конечно, новые индексы имеют нулевую прогностическую силу). – queise

1

В моем случае, я бегу искровой ALS на большом наборе данных, и данные не были доступны на всех разделах, так что я должен был кэш() данные надлежащим образом и он работал как шарм

1

Для меня, игнорируя строки полностью, задавая аргумент (https://issues.apache.org/jira/browse/SPARK-8764), на самом деле не является возможным способом решения проблемы.

Я создал свой собственный трансформатор CustomStringIndexer, который назначит новое значение для всех новых строк, которые не встречались во время обучения. Вы также можете сделать это, изменив соответствующие части кода функции искры (просто удалите условие if, явно проверяющее это и заставьте его вернуть длину массива) и перекомпилируйте банку.

Не очень легкое исправление, но это, безусловно, исправление.

Я помню, ошибка в JIRA, чтобы включить это, а также: https://issues.apache.org/jira/browse/SPARK-17498

Он установлен быть выпущен с Спарк 2.2, хотя. Просто подождите. Я думаю: S

11

С помощью Spark 2.2 (выпущено 7-2017) вы можете использовать опцию .setHandleInvalid("keep") при создании индексатора. С помощью этой опции индексщик добавляет новые индексы, когда он видит новые метки. Обратите внимание, что с предыдущими версиями у вас также есть опция "skip", которая заставляет индексатор игнорировать (удалять) строки с новыми ярлыками.

val categoryIndexerModel = new StringIndexer() 
    .setInputCol("category") 
    .setOutputCol("indexedCategory") 
    .setHandleInvalid("keep") // options are "keep", "error" or "skip" 
Смежные вопросы