Почему моя модель DecisionTreeClassifier жалуется на то, что labelCol не существует при прогнозировании? - PullRequest
0 голосов
/ 18 февраля 2019

Я начинаю писать модель ML для классификации абзацев в серии документов.Я написал свою модель, и результаты выглядят великолепно!Однако, когда я пытаюсь передать CSV, который не содержит labelCol (т. Е. Помеченный столбец, столбец, который я пытаюсь предсказать), он выдает ошибку!'Поле tagIndexed не существует.'

Так что это странно.То, что я пытаюсь предсказать, это столбец «tag», так почему он ожидал столбец «tagIndexed», когда я вызываю model.transform(df) (в Predict.scala)?У меня нет опыта работы с ML, но все DecisionTreeClassifiers, как правило, не имеют labelCol в данных тестирования.Что мне здесь не хватает?

Я создал модель, проверил ее по данным тестирования и сохранил на диск.Затем в другом объекте Scala я загружаю модель и передаю в нее свой CSV.

//Train.scala    
package com.secret.classifier
import org.apache.spark.ml.Pipeline
import org.apache.spark.ml.classification.DecisionTreeClassifier
import org.apache.spark.ml.evaluation.RegressionEvaluator
import org.apache.spark.sql.Column
import org.apache.spark.ml.feature.{HashingTF, IDF, StringIndexer, Tokenizer, VectorAssembler, Word2Vec}
import org.apache.spark.ml.regression.LinearRegression
import org.apache.spark.ml.tuning.{ParamGridBuilder, TrainValidationSplit}
import org.apache.spark.sql.functions.udf
import org.apache.spark.sql.types
import org.apache.spark.sql.types.{IntegerType, StringType, StructField, StructType}

...

val colSeq = Seq("font", "tag")
val indexSeq = colSeq.map(col => new StringIndexer().setInputCol(col).setOutputCol(col+"Indexed").fit(dfNoNan))

val tokenizer = new Tokenizer().setInputCol("soup").setOutputCol("words")
//val wordsData = tokenizer.transform(dfNoNan)

val hashingTF = new HashingTF()
.setInputCol(tokenizer.getOutputCol)
.setOutputCol("rawFeatures")
.setNumFeatures(20)

val featuresCol = "features"
val assembler = new VectorAssembler()
.setInputCols((numericCols ++ colSeq.map(_+"Indexed")).toArray)
.setOutputCol(featuresCol)

val labelCol = "tagIndexed"
val decisionTree = new DecisionTreeClassifier()
.setLabelCol(labelCol)
.setFeaturesCol(featuresCol)

val pipeline = new Pipeline().setStages((indexSeq :+ tokenizer :+ hashingTF :+ assembler :+ decisionTree).toArray)

val Array(training, test) = dfNoNan.randomSplit(Array(0.8, 0.2), seed=420420)

val model = pipeline.fit(training)


model.write.overwrite().save("tmp/spark-model")

//Predict.scala
package com.secret.classifier
import org.apache.spark.sql.functions._
import org.apache.spark.ml.{Pipeline, PipelineModel}
import org.apache.spark.ml.classification.DecisionTreeClassifier
import org.apache.spark.ml.evaluation.RegressionEvaluator
import org.apache.spark.sql.Column
import org.apache.spark.ml.feature.{HashingTF, IDF, StringIndexer, Tokenizer, VectorAssembler, Word2Vec}
import org.apache.spark.ml.regression.LinearRegression
import org.apache.spark.ml.tuning.{ParamGridBuilder, TrainValidationSplit}
import org.apache.spark.sql.types
import org.apache.spark.sql.types.{IntegerType, StringType, StructField, StructType}

...

  val dfImport = spark.read
  .format("csv")
  .option("header", "true")
  //.option("mode", "DROPMALFORMED")
  .schema(customSchema)
  .load(csvLocation)

val df = dfImport.drop("_c0", "doc_name")
df.show(20)

val model = PipelineModel.load("tmp/spark-model")

val predictions = model.transform(df)

predictions.show(20)


//pom.xml -> Spark/Scala specific dependencies
<properties>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <encoding>UTF-8</encoding>
    <scala.version>2.11.12</scala.version>
    <scala.compat.version>2.11</scala.compat.version>
    <spec2.version>4.2.0</spec2.version>
</properties>
    <dependency>
        <groupId>org.apache.spark</groupId>
        <artifactId>spark-core_2.11</artifactId>
        <version>2.3.1</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/com.databricks/spark-csv -->
    <dependency>
        <groupId>com.databricks</groupId>
        <artifactId>spark-csv_2.11</artifactId>
        <version>1.5.0</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.apache.spark/spark-sql -->
    <dependency>
        <groupId>org.apache.spark</groupId>
        <artifactId>spark-sql_2.11</artifactId>
        <version>2.3.1</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.apache.spark/spark-core -->
    <dependency>
        <groupId>org.apache.spark</groupId>
        <artifactId>spark-core_2.11</artifactId>
        <version>2.3.1</version>
    </dependency>

    <dependency>
        <groupId>com.univocity</groupId>
        <artifactId>univocity-parsers</artifactId>
        <version>2.8.0</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.apache.spark/spark-mllib -->
    <dependency>
        <groupId>org.apache.spark</groupId>
        <artifactId>spark-mllib_2.11</artifactId>
        <version>2.3.1</version>
    </dependency>
</dependencies>

Ожидаемый результат состоит в том, что модель прогнозирования не выдает ошибку.Вместо этого он выдает ошибку «Поле« tagIndexed »не существует.»

1 Ответ

0 голосов
/ 19 февраля 2019

Похоже, что вы включили поле метки в свои функции, так как оно находится в выходных данных столбца colSeq.На этом этапе вы хотите включить только столбцы объектов:

.setInputCols((numericCols ++ colSeq.map(_+"Indexed")).toArray)

Я считаю полезным использовать функцию .filterNot ().

...