我的目标是构建一个多字符分类器.
我已经构建了一个用于特征提取的管道,它包括一个StringIndexer转换器,用于将每个类名映射到一个标签,该标签将用于分类器训练步骤.
管道安装在训练集上.
测试集必须由拟合的管道处理,以便提取相同的特征向量.
知道我的测试集文件具有与训练集相同的结构.这里可能的情况是在测试集中面对一个看不见的类名,在这种情况下,StringIndexer将无法找到标签,并且将引发异常.
这种情况有解决方案吗?或者我们如何避免这种情况发生?
使用Spark 2.2(7-2017发布),您可以.setHandleInvalid("keep")
在创建索引器时使用该选项.使用此选项,索引器在看到新标签时会添加新索引.请注意,对于以前的版本,您还可以"skip"
选择,这使索引器忽略(删除)具有新标签的行.
val categoryIndexerModel = new StringIndexer() .setInputCol("category") .setOutputCol("indexedCategory") .setHandleInvalid("keep") // options are "keep", "error" or "skip"
在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"
我开始使用它,但最终回到KrisP的第二个要点,关于将这个特定的Estimator拟合到完整的数据集.
转换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
没有好办法,我很害怕.或
在应用之前过滤掉具有未知标签的测试示例 StringIndexer
或者适合StringIndexer
列车和测试数据框架的结合,因此您可以放心所有标签都在那里
或者将具有未知标签的测试示例案例转换为已知标签
以下是执行上述操作的示例代码:
// 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)))