spark实践-ML-分类-RF+多元分类评估

2018年12月15日

场景&模型选择:

根据 花的几个特征, 预测花的种类, 属于多元分类问题

花有哪几个分类?

— Iris Setosa
— Iris Versicolour
— Iris Virginica

需要哪几个特征参与模型学习?

1. sepal length in cm
2. sepal width in cm
3. petal length in cm
4. petal width in cm

分类问题常见的算法有决策树,随机森林,线性回归等, 这里使用随机森林模型RandomForestClassifier

模型评估使用ML库里的MulticlassClassificationEvaluator:
这个类位于org.apache.spark.ml.evaluation包下面,包含以下四种评估指标,我们选择使用accuracy这个指标:
* f1
* weightedPrecision
* weightedRecall
* accuracy

 

1.了解数据

数据, http://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data

数据文件有下面信息构成: 特征集合+类型标签,下面是部分数据:

5.1,3.5,1.4,0.2,Iris-setosa
4.9,3.0,1.4,0.2,Iris-setosa

7.0,3.2,4.7,1.4,Iris-versicolor
6.4,3.2,4.5,1.5,Iris-versicolor

6.3,3.3,6.0,2.5,Iris-virginica
5.8,2.7,5.1,1.9,Iris-virginica

 

2.数据预处理

先把文件中的字符串型做数值转换为Float型,  可以定义一个简单的Spark任务实现,在保存在文件Iris_data.txt 或其他存储介质中

5.1,3.5,1.4,0.2,0.0
4.9,3.0,1.4,0.2,0.0

7.0,3.2,4.7,1.4,1.0
6.4,3.2,4.5,1.5,1.0

6.3,3.3,6.0,2.5,2.0
5.8,2.7,5.1,1.9,2.0

Iris_data.txt 中文件加载数据转换成DF格式

   val df = parseRDD(sc.textFile("/Iris_data.txt")).map(parseIris).toDF().cache()

    val featureCols = Array("sepal_length", "sepal_width", "petal_length", "petal_width", "Iris_class")

相关结构和子函数定义:

  case class Iris(
                   sepal_length: Float,
                   sepal_width: Float, petal_length: Float, petal_width: Float, Iris_class: Float
                 )

  def parseIris(line: Array[Float]): Iris = {
    Iris(
      line(0),
      line(1) - 1, line(2), line(3), line(4)
    )
  }

  def parseRDD(rdd: RDD[String]): RDD[Array[Float]] = {
    rdd.map(_.split(",")).map(_.map(_.toFloat))
  }

 

特征列向量集featureCols生成相关特征索引列features,  标签列Iris_class生成相关索引列label, 再把数据集 分为训练集,验证集

VectorAssembler是一个transformer,将多列数据转化为单列的向量列

    val assembler = new VectorAssembler().setInputCols(featureCols).setOutputCol("features")
    val df2 = assembler.transform(df)

    val labelIndexer = new StringIndexer().setInputCol("Iris_class").setOutputCol("label")
    val df3 = labelIndexer.fit(df2).transform(df2)

    val Array(trainingData, testData) = df3.randomSplit(Array(0.7, 0.3), 5000)

 

2.模型pipeline定义

分类问题可以使用的算法很多, 个人比较常用随机森林;  分类器使用多元分类器:   MulticlassClassificationEvaluator

配置paramGrid 进行自动调试模型参数, 运行生成模型

    val classifier = new RandomForestClassifier()
    val model = classifier.fit(trainingData)

    val evaluator = new MulticlassClassificationEvaluator().setLabelCol("label").setPredictionCol("prediction")

    val paramGrid = new ParamGridBuilder()
      .addGrid(classifier.maxBins, Array(25, 31))
      .addGrid(classifier.maxDepth, Array(5, 10))
      .addGrid(classifier.numTrees, Array(20, 60))
      .addGrid(classifier.impurity, Array("entropy", "gini"))
      .build()

    val steps: Array[PipelineStage] = Array(classifier)
    val pipeline = new Pipeline().setStages(steps)

    val cv = new CrossValidator()
      .setEstimator(pipeline)
      .setEvaluator(evaluator)
      .setEstimatorParamMaps(paramGrid)
      .setNumFolds(10)

    val pipelineFittedModel = cv.fit(trainingData)

模型预测与评估

    val predictions = pipelineFittedModel.transform(testData)
    predictions.show()

模型评估时主要使用label 和prediction 2列的差异

+————+———–+————+———–+———-+——————–+—–+————-+———–+———-+
|sepal_length|sepal_width|petal_length|petal_width|Iris_class| features|label|rawPrediction|probability|prediction|
+————+———–+————+———–+———-+——————–+—–+————-+———–+———-+
| 4.3| 2.0| 1.1| 0.1| 0.0|[4.30000019073486…| 1.0| [0.0,20.0]| [0.0,1.0]| 1.0|
| 4.4| 2.2| 1.3| 0.2| 0.0|[4.40000009536743…| 1.0| [0.0,20.0]| [0.0,1.0]| 1.0|
| 4.7| 2.2| 1.3| 0.2| 0.0|[4.69999980926513…| 1.0| [0.0,20.0]| [0.0,1.0]| 1.0|
| 4.7| 2.2| 1.6| 0.2| 0.0|[4.69999980926513…| 1.0| [0.0,20.0]| [0.0,1.0]| 1.0|
| 4.8| 2.4| 1.9| 0.2| 0.0|[4.80000019073486…| 1.0| [2.0,18.0]| [0.1,0.9]| 1.0|
| 5.0| 2.2| 1.2| 0.2| 0.0|[5.0,2.2000000476…| 1.0| [0.0,20.0]| [0.0,1.0]| 1.0|
| 5.0| 2.4| 1.6| 0.4| 0.0|[5.0,2.4000000953…| 1.0| [0.0,20.0]| [0.0,1.0]| 1.0|
| 5.0| 2.5| 1.3| 0.3| 0.0|[5.0,2.5,1.299999…| 1.0| [0.0,20.0]| [0.0,1.0]| 1.0|
| 5.0| 2.6| 1.4| 0.2| 0.0|[5.0,2.5999999046…| 1.0| [0.0,20.0]| [0.0,1.0]| 1.0|
| 5.2| 2.4| 1.4| 0.2| 0.0|[5.19999980926513…| 1.0| [0.0,20.0]| [0.0,1.0]| 1.0|
| 5.4| 2.4| 1.7| 0.2| 0.0|[5.40000009536743…| 1.0| [0.0,20.0]| [0.0,1.0]| 1.0|
| 5.4| 2.9| 1.3| 0.4| 0.0|[5.40000009536743…| 1.0| [0.0,20.0]| [0.0,1.0]| 1.0|
| 5.5| 1.4000001| 3.7| 1.0| 1.0|[5.5,1.4000000953…| 0.0| [20.0,0.0]| [1.0,0.0]| 0.0|
| 5.5| 1.5999999| 4.4| 1.2| 1.0|[5.5,1.5999999046…| 0.0| [20.0,0.0]| [1.0,0.0]| 0.0|
| 5.5| 3.1999998| 1.4| 0.2| 0.0|[5.5,3.1999998092…| 1.0| [0.0,20.0]| [0.0,1.0]| 1.0|
| 5.6| 1.7| 4.2| 1.3| 1.0|[5.59999990463256…| 0.0| [20.0,0.0]| [1.0,0.0]| 0.0|
| 5.6| 1.9000001| 3.6| 1.3| 1.0|[5.59999990463256…| 0.0| [20.0,0.0]| [1.0,0.0]| 0.0|
| 5.6| 2.0| 4.1| 1.3| 1.0|[5.59999990463256…| 0.0| [20.0,0.0]| [1.0,0.0]| 0.0|
| 5.6| 2.0| 4.5| 1.5| 1.0|[5.59999990463256…| 0.0| [20.0,0.0]| [1.0,0.0]| 0.0|
| 5.7| 1.5| 5.0| 2.0| 1.0|[5.69999980926513…| 0.0| [20.0,0.0]| [1.0,0.0]| 0.0|

    val accuracy = evaluator.evaluate(predictions)
    println("accuracy before pipeline fitting" + accuracy)

    println(pipelineFittedModel.bestModel.asInstanceOf[org.apache.spark.ml.PipelineModel].stages(0))

评估结果:  生成的20颗树的随机森林模型, 预测精准度如下:

accuracy  fitting  0.97
RandomForestClassificationModel (uid=rfc_d9c752e11bd5) with 20 trees

没有评论

发表评论

邮箱地址不会被公开。 必填项已用*标注