feel 发表于 2016-4-6 11:46:50

机器学习实战之SVM

支持向量机 主要用在分类问题上,其效果也是非常好的。下面代码是基于sparkML lib svm 算法的实现
package com.gizwits.mllib

import org.apache.log4j.{Level, Logger}
import org.apache.spark.mllib.classification.SVMWithSGD
import org.apache.spark.mllib.evaluation.{BinaryClassificationMetrics, MulticlassMetrics}
import org.apache.spark.mllib.optimization.{HingeGradient, L1Updater}
import org.apache.spark.mllib.util.MLUtils
import org.apache.spark.{SparkConf, SparkContext}

/**
* Created by feel
* <p>
*
* SVM(线性支持向量机)是一个有监督的学习模型,通常用来进行模式识别、分类、以及回归分析。SVM只支持二分类
*
* </p>
*
*/
object SparkSVM {


def main(args: Array) {
    //设置日志级别
    val rootLogger = Logger.getRootLogger()

    Logger.getLogger("com.gizwits").setLevel(Level.ERROR)


    val conf = new SparkConf().setAppName("SparkSVM").setMaster("local")
    val sc = new SparkContext(conf)

    /*
      数据解释,如下,第一个是标签也就是分类,0 表示1类,1表示另一类.冒号2边 表示 特征维度:特征值, 如 128:51表示 第128维度, 特征值为51,比如单词出现的 次数
      0 128:51 129:159
      1 159:124 160:253b
      1 159:124 160:253
   */
    val dataInputPath = "file:///Users/feel/githome/idea/spark-exercise/src/main/resources/sample_libsvm_data.txt"
    // 加载 LIBSVM 格式的数据
    val data = MLUtils.loadLibSVMFile(sc, dataInputPath)

    // 切分数据,60%用于训练,40%用于测试
    val splits = data.randomSplit(Array(0.6, 0.4), seed = 11L)
    // 60% 用于训练训练集,RDD
    val training = splits(0).cache()

    //40% 用于测试
    val test = splits(1)

    // 运行训练算法 来构建模型
    val numIterations = 200 // 迭代次数,默认是100
    /**
      * SVMWithSGD类中参数说明:
      *
      * stepSize: 迭代步长,默认为1.0
      *
      * numIterations: 迭代次数,默认为100
      *
      * regParam: 正则化参数,默认值为0.0
      *
      * miniBatchFraction: 每次迭代参与计算的样本比例,默认为1.0
      *
      * gradient:HingeGradient (),梯度下降; 其损失函数是 hinge los
      *
      * updater:SquaredL2Updater (),正则化,L2范数;线性SVM使用L2正则化做训练。也可以替换为L1正则化,这样就成了线性优化问题
      *
      * optimizer:GradientDescent (gradient, updater),梯度下降最优化计算。
      */
   // val model =SVMWithSGD.train(data, iterations=100, step=1.0, regParam=0.01, miniBatchFraction=1.0, initialWeights=None, regType=’l2′, intercept=False)
    //val model = SVMWithSGD.train(training, numIterations) // 随机梯度下降法 简单模式


    val svmAlg = new SVMWithSGD()

    /**
      * 为了防止过拟合,需要在loss function后面加入一个正则化项一起求最小值。
      * 正则化项相当于对weights向量的惩罚,期望求出一个更简单的模型。
      * MLlib目前支持两种正则化方法L1和L2。
      * L2正则化假设模型参数服从高斯分布,L2正则化函数比L1更光滑,所以更容易计算;
      * L1假设模型参数服从拉普拉斯分布,L1正则化具备产生稀疏解的功能,从而具备feature selection的能力。
      */
    svmAlg.optimizer
      .setGradient(new HingeGradient()) // HingeGradient,支持ANNGradient,LogisticGradient,LeastSquaresGradient
      .setNumIterations(numIterations)
      .setRegParam(0.1). //设置正则化参数
      setUpdater(new L1Updater) //目前支持 SquaredL2Updater,ANNUpdater,SimpleUpdater


    val model = svmAlg.run(training)


    // 清空默认值
    model.clearThreshold()

    // 用训练集计算原始分数
    val scoreAndLabels = test.map { point =>
      val score = model.predict(point.features)
      (score, point.label)
    }
    //训练数据集用RDD表示,其中label是分类类型的索引,从0开始,即0, 1, 2, …。
    val result = scoreAndLabels.map { t =>
      val str = "point.label=" + t._2 + " score= " + t._1
      println(str)
      str
    }
    result.collect()

    // 以下是2种分类模型的评估
    // 获得评价指标,二分类评估

    /**
      * ROC的全名叫做Receiver Operating Characteristic,是一个画在二维平面上的经过(0, 0),(1, 1)的曲线,
      * 一般情况下,这个曲线都应该处于(0, 0)和(1, 1)连线的上方,如果不幸的出现在了下方,说明分类器的结果反了。
      * 程序里的结果其实是计算的AUC,也就是Area Under roc Curve,
      * 也就是处于ROC curve下方的那部分面积的大小,一般是0.5至1,越大就说明分类效果越好
      */
    val metrics = new BinaryClassificationMetrics(scoreAndLabels)
    val auROC = metrics.areaUnderROC() //受试者操作特征
    println("Area under ROC = " + auROC)

    // 计算测试误差,多分类

    val metricsLabel = new MulticlassMetrics(scoreAndLabels)

    val precision = metricsLabel.precision

    println("Precision = " + precision)
    sc.stop()
}
}



页: [1]
查看完整版本: 机器学习实战之SVM