• SparkMLlib分类算法之决策树学习


    SparkMLlib分类算法之决策树学习

    (一) 决策树的基本概念

        决策树(Decision Tree)是在已知各种情况发生概率的基础上,通过构成决策树来求取净现值的期望值大于等于零的概率,评价项目风险,判断其可行性的决策分析方法,是直观运用概率分析的一种图解法。由于这种决策分支画成图形很像一棵树的枝干,故称决策树。在机器学习中,决策树是一个预测模型,他代表的是对象属性与对象值之间的一种映射关系。Entropy = 系统的凌乱程度,使用算法ID3, C4.5和C5.0生成树算法使用熵。这一度量是基于信息学理论中熵的概念。通过信息增益来筛选出属性的优先性。

     缺点:参考网址:http://www.ppvke.com/Blog/archives/25042

    1)对连续性的字段比较难预测。
    2)对有时间顺序的数据,需要很多预处理的工作。
    3)当类别太多时,错误可能就会增加的比较快。
    4)一般的算法分类的时候,只是根据一个字段来分类。
     
    (二) SparkMLlib对决策树应用
    1,数据集的准备:参考:http://www.cnblogs.com/ksWorld/p/6882398.html
    2,数据预处理及获取训练集和测试集
    val orig_file=sc.textFile("train_nohead.tsv")
        //println(orig_file.first())
        val data_file=orig_file.map(_.split("	")).map{
          r =>
            val trimmed =r.map(_.replace(""",""))
            val lable=trimmed(r.length-1).toDouble
            val feature=trimmed.slice(4,r.length-1).map(d => if(d=="?")0.0
            else d.toDouble)
            LabeledPoint(lable,Vectors.dense(feature))
        }
       /*特征标准化优化,似乎对决策数没啥影响*/
        val vectors=data_file.map(x =>x.features)
        val rows=new RowMatrix(vectors)
        println(rows.computeColumnSummaryStatistics().variance)//每列的方差
        val scaler=new StandardScaler(withMean=true,withStd=true).fit(vectors)//标准化
        val scaled_data=data_file.map(point => LabeledPoint(point.label,scaler.transform(point.features)))
            .randomSplit(Array(0.7,0.3),11L)//固定seed为11L,确保每次每次实验能得到相同的结果
        val data_train=scaled_data(0)
        val data_test=scaled_data(1)

    3,构建模型及模型评价

    /*训练决策树模型*/
        val model_DT=DecisionTree.train(data_train,Algo.Classification,Entropy,maxTreeDepth)
     /*决策树的精确度*/
        val predectionAndLabeledDT=data_test.map { point =>
          val predectLabeled = if (model_DT.predict(point.features) > 0.5) 1.0 else 0.0
          (predectLabeled,point.label)
        }
        val metricsDT=new MulticlassMetrics(predectionAndLabeledDT)
        println(metricsDT.accuracy)//0.6273062730627307
    /*决策树的PR曲线和AOC曲线*/
        val dtMetrics = Seq(model_DT).map{ model =>
          val scoreAndLabels = data_test.map { point =>
            val score = model.predict(point.features)
            (if (score > 0.5) 1.0 else 0.0, point.label)
          }
          val metrics = new BinaryClassificationMetrics(scoreAndLabels)
          (model.getClass.getSimpleName, metrics.areaUnderPR, metrics.areaUnderROC)
        }
        val allMetrics = dtMetrics
        allMetrics.foreach{ case (m, pr, roc) =>
          println(f"$m, Area under PR: ${pr * 100.0}%2.4f%%, Area under ROC: ${roc * 100.0}%2.4f%%")
        }
    /*
    DecisionTreeModel, Area under PR: 74.2335%, Area under ROC: 62.4326%
    */

    4,模型参数调优(可以调解长度和纯度两方面考虑)

    4.1 构建调参函数

    /*调参函数*/
        def trainDTWithParams(input: RDD[LabeledPoint], maxDepth: Int,
                              impurity: Impurity) = {
          DecisionTree.train(input, Algo.Classification, impurity, maxDepth)
        }

    4.2  调解树的深度评估函数  (提高树的深度可以得到更精确的模型(这和预期一致,因为模型在更大的树深度下会变得更加复杂)。然而树的深度越大,模型对训练数据过拟合程度越严重)

     /*改变深度*/
        val dtResultsEntropy = Seq(1, 2, 3, 4, 5, 10, 20).map { param =>
          val model = trainDTWithParams(data_train, param, Entropy)
          val scoreAndLabels = data_test.map { point =>
            val score = model.predict(point.features)
            (if (score > 0.5) 1.0 else 0.0, point.label)
          }
          val metrics = new BinaryClassificationMetrics(scoreAndLabels)
          (s"$param tree depth", metrics.areaUnderROC)
        }
        dtResultsEntropy.foreach { case (param, auc) => println(f"$param, " +
          f"AUC = ${auc * 100}%2.2f%%") }
    /*
    1 tree depth, AUC = 58.57%
    2 tree depth, AUC = 60.69%
    3 tree depth, AUC = 61.40%
    4 tree depth, AUC = 61.30%
    5 tree depth, AUC = 62.43%
    10 tree depth, AUC = 62.26%
    20 tree depth, AUC = 60.59%
    */

    2,调解纯度参数 (差异不是很明显。。)

     /*改变纯度*/
        val dtResultsEntropy = Seq(Gini,Entropy).map { param =>
          val model = trainDTWithParams(data_train, 5, param)
          val scoreAndLabels = data_test.map { point =>
            val score = model.predict(point.features)
            (if (score > 0.5) 1.0 else 0.0, point.label)
          }
          val metrics = new BinaryClassificationMetrics(scoreAndLabels)
          (s"$param tree depth", metrics.areaUnderROC)
        }
        dtResultsEntropy.foreach { case (param, auc) => println(f"$param, " +
          f"AUC = ${auc * 100}%2.2f%%") }
    /*
    org.apache.spark.mllib.tree.impurity.Gini$@32d8e58d tree depth, AUC = 62.37%
    org.apache.spark.mllib.tree.impurity.Entropy$@1ddba7a0 tree depth, AUC = 62.43%
    */

    (三) 交叉验证

    1,数据集分类

    创建三个数据集:训练集

    评估集(类似上述测试集用于模型参数的调优,比如 lambda 和步长)

    测试集(不用于模型的训练和参数调优,只用于估计模型在新数据中性能)

    2,交叉验证的常用方法

    一个流行的方法是 K- 折叠交叉验证,其中数据集被分成 K 个不重叠的部分。用数据中的 K-1 份训练模型,剩下一部分测试模型。而只分训练集和测试集可以看做是 2- 折叠交叉验证。

    还有“留一交叉验证”和“随机采样”。更多资料详见 http://en.wikipedia.org/wiki/Cross-validation_(statistics) 。

  • 相关阅读:
    source命令
    bash中单引号与双引号的总结
    鸟哥的linux私房菜学习笔记3
    鸟哥的linux私房菜学习笔记2
    /usr/sbin/atd 和 /etc/init.d/atd有什么区别
    Linux中/etc/fstab /etc/mtab /proc/mounts这三个文件的分析与比较
    服务器本机不能登陆的解决
    有用的博客
    推荐几个好用的PHP集成开发环境
    ANDROID开发笔记(二)
  • 原文地址:https://www.cnblogs.com/ksWorld/p/6884313.html
Copyright © 2020-2023  润新知