当前位置:  开发笔记 > 编程语言 > 正文

Spark,ML,StringIndexer:处理看不见的标签

如何解决《Spark,ML,StringIndexer:处理看不见的标签》经验,为你挑选了3个好方法。

我的目标是构建一个多字符分类器.

我已经构建了一个用于特征提取的管道,它包括一个StringIndexer转换器,用于将每个类名映射到一个标签,该标签将用于分类器训练步骤.

管道安装在训练集上.

测试集必须由拟合的管道处理,以便提取相同的特征向量.

知道我的测试集文件具有与训练集相同的结构.这里可能的情况是在测试集中面对一个看不见的类名,在这种情况下,StringIndexer将无法找到标签,并且将引发异常.

这种情况有解决方案吗?或者我们如何避免这种情况发生?



1> queise..:

使用Spark 2.2(7-2017发布),您可以.setHandleInvalid("keep")在创建索引器时使用该选项.使用此选项,索引器在看到新标签时会添加新索引.请注意,对于以前的版本,您还可以"skip"选择,这使索引器忽略(删除)具有新标签的行.

val categoryIndexerModel = new StringIndexer()
  .setInputCol("category")
  .setOutputCol("indexedCategory")
  .setHandleInvalid("keep") // options are "keep", "error" or "skip"



2> Chris Fregly..:

在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


但是当您尝试将模型应用于新数据时会发生什么?您可能会发现某些列中有新值不在原始测试或训练数据中.我担心setHandleInvalid("skip")将导致整行被丢弃,当你真的只想忽略以前看不见的值时,仍然使用行中的其他值.

3> KrisP..:

没有好办法,我很害怕.或

在应用之前过滤掉具有未知标签的测试示例 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)))

推荐阅读
女女的家_747
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有