首页 > BigData, 技术,让世界更美好。 > 【spark】【machine learning】机器学习算法效果评估方法————分类模型的评估

【spark】【machine learning】机器学习算法效果评估方法————分类模型的评估

2017年1月17日

spark.mllib附带了许多机器学习算法,可用于学习和预测数据。当这些算法应用于构建机器学习模型时,需要根据某些标准来评估模型的性能,这取决于应用程序及其要求。 spark.mllib还提供了一套度量标准,用于评估机器学习模型的性能。
特定的机器学习算法属于更广泛类型的机器学习应用程序,如分类,回归,聚类等。这些类型中的每一种都具有良好的性能评估指标,本文章将详细介绍spark.mllib中当前可用的指标。

1. 分类模型评估(Classification model evaluation)

虽然存在许多不同类型的分类算法,但是分类模型的评估都具有相似的原理。在监督分类问题中,对于每个数据点存在真实输出和模型生成的预测输出。因此,每个数据点的结果可以分配到以下四个类别之一:

  • 真阳性(TP) – 标签是阳性,预测也是阳性
  • 真阴性(TN) – 标签为负值,预测也是阴性
  • 假阳性(FP) – 标签为阴性,但预测为阳性
  • 假阴性(FN) – 标签为正,但预测为阴性

这四个数字是大多数分类器评估指标的基础。当评估分类器的用基本的纯准确度(即,预测正确或不正确)通常不能良好的评估分类器。其原因是因为数据集可能是高度不平衡的。

例如,如果模型设计为从95%正常数据混合5%的诈骗数据的数据集中预测诈骗数据,则不管输入如何,预测不欺诈的分类器将是95 %准确。为此,通常使用诸如准确率和召回率(precision and recall )的度量,因为它们考虑了错误的类型。在大多数应用中,在准确率和召回率之间存在一些期望的平衡,这可以通过将两者组合成称为F值( F-measure)。

1.1 二元分类(Binary classification)

        二元分类器用于将给定数据集的元素分成两个可能的组(例如诈骗或非诈骗)中的一个,并且作为多类分类的特殊情况。大多数二元分类评估指标可以推广到多类分类评估。

1.1.1  阈值调谐(Threshold tuning)

可以理解为,许多分类模型实际上为每个类输出“分数”(通常乘以概率),其中较高的分数表示较高的可能性。在二元情况下,模型可以输出每个类别的概率:P(Y = 1 | X)和P(Y = 0 | X)。代替简单地采取较高的概率,可能存在这样的情况,其中模型可能需要被调整,使得它仅当概率非常高时才预测类别(例如,如果模型预测欺诈具有大于90的诈骗,则仅阻止信用卡交易%概率)。因此,存在预测阈值,其基于模型输出的概率来确定预测类别将是什么。

调整预测阈值将改变模型的准确率和召回率,并且是模型优化的重要部分。为了可视化精确度,回忆和其他度量如何作为阈值的函数而变化,通常的做法是通过阈值来参数化彼此竞争的度量。 P-R曲线绘制不同阈值的点(精确度,召回率)点,而接收器操作特征或ROC曲线图(召回率,假阳性率)点。

用到的指标

代码实例:

import org.apache.spark.mllib.classification.LogisticRegressionWithLBFGS
import org.apache.spark.mllib.evaluation.BinaryClassificationMetrics
import org.apache.spark.mllib.regression.LabeledPoint
import org.apache.spark.mllib.util.MLUtils

// Load training data in LIBSVM format
val data = MLUtils.loadLibSVMFile(sc, "data/mllib/sample_binary_classification_data.txt")

// Split data into training (60%) and test (40%)
val Array(training, test) = data.randomSplit(Array(0.6, 0.4), seed = 11L)
training.cache()

// Run training algorithm to build the model
val model = new LogisticRegressionWithLBFGS()
  .setNumClasses(2)
  .run(training)

// Clear the prediction threshold so the model will return probabilities
model.clearThreshold

// Compute raw scores on the test set
val predictionAndLabels = test.map { case LabeledPoint(label, features) =>
  val prediction = model.predict(features)
  (prediction, label)
}

// Instantiate metrics object
val metrics = new BinaryClassificationMetrics(predictionAndLabels)

// Precision by threshold
val precision = metrics.precisionByThreshold
precision.foreach { case (t, p) =>
  println(s"Threshold: $t, Precision: $p")
}

// Recall by threshold
val recall = metrics.recallByThreshold
recall.foreach { case (t, r) =>
  println(s"Threshold: $t, Recall: $r")
}

// Precision-Recall Curve
val PRC = metrics.pr

// F-measure
val f1Score = metrics.fMeasureByThreshold
f1Score.foreach { case (t, f) =>
  println(s"Threshold: $t, F-score: $f, Beta = 1")
}

val beta = 0.5
val fScore = metrics.fMeasureByThreshold(beta)
f1Score.foreach { case (t, f) =>
  println(s"Threshold: $t, F-score: $f, Beta = 0.5")
}

// AUPRC
val auPRC = metrics.areaUnderPR
println("Area under precision-recall curve = " + auPRC)

// Compute thresholds used in ROC and PR curves
val thresholds = precision.map(_._1)

// ROC Curve
val roc = metrics.roc

// AUROC
val auROC = metrics.areaUnderROC
println("Area under ROC = " + auROC)

1.2多类分类(Multiclass classification)

多类别分类描述了一个分类问题,其中每个数据点有M> 2个可能的标签(当M = 2就是二元分类问题的情况)。例如,将手写样本分类为数字0到9,具有10个可能的类。

对于多类度量,正和负的概念略有不同。预测和标签仍然可以是正面或负面的,但是它们必须在特定类的上下文中考虑。每个标签和预测采用多个类中的一个的值,因此它们对于它们的特定类是正的,对于所有其他类是负的。因此,每当预测和标签匹配时发生真阳性,而当预测和标记都不采用给定类的值时,发生真阴性。按照这个约定,对于给定的数据样本可以有多个真阴性。来自正和负标签的以前定义的假阴性和假阳性的扩展是直接的。

基于标签的指标(Label based metrics)

与仅存在两个可能标签的二元分类相反,多类分类问题具有许多可能的标签,因此引入了基于标签的度量的概念。所有标签的总体精确度- 任何类正确预测的次数(真阳性),通过数据点的数量归一化。标签精确度仅考虑一个类别,对于一个具体的标签 通过标签在输出中出现的次数统计标签预测正确的归一值。

可能用到的指标(Available metrics)

多类分类2

多类分类

代码实例:

import org.apache.spark.mllib.classification.LogisticRegressionWithLBFGS
import org.apache.spark.mllib.evaluation.MulticlassMetrics
import org.apache.spark.mllib.regression.LabeledPoint
import org.apache.spark.mllib.util.MLUtils

// Load training data in LIBSVM format
val data = MLUtils.loadLibSVMFile(sc, "data/mllib/sample_multiclass_classification_data.txt")

// Split data into training (60%) and test (40%)
val Array(training, test) = data.randomSplit(Array(0.6, 0.4), seed = 11L)
training.cache()

// Run training algorithm to build the model
val model = new LogisticRegressionWithLBFGS()
  .setNumClasses(3)
  .run(training)

// Compute raw scores on the test set
val predictionAndLabels = test.map { case LabeledPoint(label, features) =>
  val prediction = model.predict(features)
  (prediction, label)
}

// Instantiate metrics object
val metrics = new MulticlassMetrics(predictionAndLabels)

// Confusion matrix
println("Confusion matrix:")
println(metrics.confusionMatrix)

// Overall Statistics
val precision = metrics.precision
val recall = metrics.recall // same as true positive rate
val f1Score = metrics.fMeasure
println("Summary Statistics")
println(s"Precision = $precision")
println(s"Recall = $recall")
println(s"F1 Score = $f1Score")

// Precision by label
val labels = metrics.labels
labels.foreach { l =>
  println(s"Precision($l) = " + metrics.precision(l))
}

// Recall by label
labels.foreach { l =>
  println(s"Recall($l) = " + metrics.recall(l))
}

// False positive rate by label
labels.foreach { l =>
  println(s"FPR($l) = " + metrics.falsePositiveRate(l))
}

// F-measure by label
labels.foreach { l =>
  println(s"F1-Score($l) = " + metrics.fMeasure(l))
}

// Weighted stats
println(s"Weighted precision: ${metrics.weightedPrecision}")
println(s"Weighted recall: ${metrics.weightedRecall}")
println(s"Weighted F1 score: ${metrics.weightedFMeasure}")
println(s"Weighted false positive rate: ${metrics.weightedFalsePositiveRate}")
本文的评论功能被关闭了.