SparkMLlib学习之线性回归

(一)回归的概念

  1,回归与分类的区别

   分类模型处理表示类别的离散变量,而回归模型则处理可以取任意实数的目标变量。但是二者基本的原则类似,都是通过确定一个模型,将输入特征映射到预测的输出。回归模型和分类模型都是监督学习的一种形式。

  2.回归分类

   线性回归模型:本质上和对应的线性分类模型一样,唯一的区别是线性回归使用的损失函数、相关连接函数和决策函数不同。MLlib提供了标准的最小二乘回归模型在MLlib中,标准的最小二乘回归不使用正则化。但是应用到错误预测值的损失函数会将错误做平方,从而放大损失。这也意味着最小平方回归对数据中的异常点和过拟合非常敏感。因此对于分类器,我们通常在实际中必须应用一定程度的正则化。正则化分为:应用L2正则化时通常称为岭回归(ridge regression),应用L1正则化是称为LASSO(Least Absolute Shrinkage and Selection Operator)。

   决策树模型:决策树同样可以通过改变不纯度的度量方法用于回归分析

(二)SparkMLlib线性回归的应用

  1,数据集的选择

    http://archive.ics.uci.edu/ml/datasets/Bike+Sharing+Dataset。

  2.数据集的描述

    此数据是根据一系列的特征预测每小时自行车租车次数,特征类型如下:

  3,数据处理及构建模型

    数据集中共有17 379个小时的记录。接下来的实验,我们会忽略记录中的 instant和 dteday 。忽略两个记录次数的变量 casual 和 registered ,只保留 cnt ( casual 和registered 的和)。最后就剩下12个变量,其中前8个是类型变量,后4个是归一化后的实数变量。对其中8个类型变量,我们使用之前提到的二元编码,剩下4个实数变量不做处理。另外一种二元变量化方法:http://blog.csdn.net/u010824591/article/details/50374904

import org.apache.log4j.{Level, Logger}
import org.apache.spark.mllib.linalg.Vectors
import org.apache.spark.mllib.regression.{LabeledPoint, LinearRegressionWithSGD}
import org.apache.spark.mllib.tree.DecisionTree
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext} /**
* Created by Damon on 17-5-22.
*/
object Regression {
def main(args: Array[String]): Unit = {
Logger.getLogger("org.apache.spark").setLevel(Level.WARN)
Logger.getLogger("org.eclipse.jetty.server").setLevel(Level.OFF)
val conf =new SparkConf().setAppName("regression").setMaster("local[4]")
val sc =new SparkContext(conf)
//文件名
val file_bike="hour_nohead.csv"
//调用二元向量化方法
val labeled_file=labeledFile(file_bike,sc)
/*/*对目标值取对数*/
val labeled_file1=labeled_file.map(point => LabeledPoint(math.log(point.label),point.features))
*/
//构建线性回归模型,注该方法在:spark2.1.0已经抛弃了。。。。
val model_liner=LinearRegressionWithSGD.train(labeled_file,10,0.1)
//val categoricalFeaturesInfo = Map[Int,Int]()
//val model_DT=DecisionTree.trainRegressor(labeled_file,categoricalFeaturesInfo,"variance",5,32)
val predict_vs_train=labeled_file.map{
point => (model_liner.predict(point.features),point.label)
//对目标取对数后的,预测方法
/* point => (math.exp(model_liner.predict(point.features)),math.exp(point.label))*/
}
predict_vs_train.take(5).foreach(println(_))
/*
(135.94648455498356,16.0)
(134.38058174607252,40.0)
(134.1840793861374,32.0)
(133.88699144084515,13.0)
(133.77899037657548,1.0)
*/
def labeledFile(originFile:String,sc:SparkContext):RDD[LabeledPoint]={
val file_load=sc.textFile(originFile)
val file_split=file_load.map(_.split(","))
/*构建映射类函数的方法:mapping*/
def mapping(rdd:RDD[Array[String]],index:Int)=
rdd.map(x => x(index)).distinct.zipWithIndex().collect.toMap
/*存储每列映射方法mapping的maps集合*/
var maps:Map[Int,Map[String,Long]] = Map()
/* 生成maps*/
for(i <- 2 until 10)
maps += (i -> mapping(file_split,i))
/*max_size表示每列的特征之和*/
val max_size=maps.map(x =>x._2.size).sum
val file_label=file_split.map{
x =>
var num:Int=0
var size:Int=0
/*构建长度为max_size+4的特征数组,初始值全为0*/
val arrayOfDim=Array.ofDim[Double](max_size+4)
for(j<-2 until 10) {
num = maps(j)(x(j)).toInt
if(j==2) size=0 else size += maps(j-1).size
/*为特征赋值*/
arrayOfDim(size+num)=1.0
}
/*添加后面4列归一化的特征*/
for(j<-10 until 14)
arrayOfDim(max_size+(j-10))=x(j).toDouble
/*生成LabeledPoint类型*/
LabeledPoint(x(14).toDouble+x(15).toDouble,Vectors.dense(arrayOfDim))
}
file_label
}
}

  4,模型性能评价

    (1) MSE是均方误差,是用作最小二乘回归的损失函数,表示所有样本预测值和实际值平方差的平均值。公式如下:

    (2)RMSE是MSE的平方根    

    (3)平均绝对误差(MAE):预测值与实际值的绝对值差的平均值

            

    (4) 均方根对数误差(RMSLE):预测值和目标值进行对数变换后的RMSE.

代码如下:

/*MSE是均方误差*/
val mse=predict_vs_train.map(x => math.pow(x._1-x._2,2)).mean()
/* 平均绝对误差(MAE)*/
val mae=predict_vs_train.map(x => math.abs(x._1-x._2)).mean()
/*均方根对数误差(RMSLE)*/
val rmsle=math.sqrt(predict_vs_train.map(x => math.pow(math.log(x._1+1)-math.log(x._2+1),2)).mean())
println(s"mse is $mse and mae is $mae and rmsle is $rmsle")
/*
mse is 29897.34020145107 and mae is 130.53255991178477 and rmsle is 1.4803867063174845
*/

(三) 改进模型性能和参数调优

  1,变换目标变量

   许多机器学习模型都会假设输入数据和目标变量的分布,比如线性模型的假设为正态分布,这里就将目标值取对数(还可以去sqrt处理)(将上文注释去掉)实现正态分布,结果如为:mse is 47024.572159822106 and mae is 149.28861881845546 and rmsle is 1.4525632598540426

  将上述结果和原始数据训练的模型性能比较,可以看到我们提升了RMSLE的性能,但是却没有提升MSE和MAE的性能。

  2.交叉验证

   1,创建训练集和测试集来评估参数

   2,调节参数来判断对线性模型的影响

迭代次数及步长的影响:

//划分训练集和测试集
val labeled_orign = labeled_file.randomSplit(Array(0.8, 0.2), 11L)
val train_file = labeled_orign()
val test_file = labeled_orign()
/*调节迭代次数*/
val Iter_Results = Seq(, , , , , ).map { param =>
val model = LinearRegressionWithSGD.train(test_file, param, 0.01)
val scoreAndLabels = test_file.map { point =>
(model.predict(point.features), point.label)
}
val rmsle = math.sqrt(scoreAndLabels.map(x => math.pow(math.log(x._1) - math.log(x._2), )).mean)
(s"$param lambda", rmsle)
}
/*迭代次数的结果输出*/
Iter_Results.foreach { case (param, rmsl) => println(f"$param, rmsle = ${rmsl}")}
/*调节步长数的大小*/
val Step_Results = Seq(0.01, 0.025, 0.05, 0.1, 1.0).map { param =>
val model = LinearRegressionWithSGD.train(test_file, , param)
val scoreAndLabels = test_file.map { point =>
(model.predict(point.features), point.label)
}
val rmsle = math.sqrt(scoreAndLabels.map(x => math.pow(math.log(x._1) - math.log(x._2), )).mean)
(s"$param lambda", rmsle)
}
/*步长的结果输出*/
Step_Results.foreach { case (param, rmsl) => println(f"$param, rmsle = ${rmsl}")}
/*results
1 lambda, rmsle = 2.9033629718241167
5 lambda, rmsle = 2.0102924520366092
10 lambda, rmsle = 1.7548482896314488
20 lambda, rmsle = 1.5785106813100764
50 lambda, rmsle = 1.461748782192306
100 lambda, rmsle = 1.4462810196387068
步长
0.01 lambda, rmsle = 1.5785106813100764
0.025 lambda, rmsle = 1.4478358250917658
0.05 lambda, rmsle = 1.5152549319928832
0.1 lambda, rmsle = 1.5687431700715837
1.0 lambda, rmsle = NaN
*/

  结果表明,随着迭代次数的增加,误差确实有所下降(即性能提高),并且下降速率和预期一样越来越小。可以看出为什么不使用默认步长来训练线性模型。其中默认步长为1.0,得到的RMSLE结果为 nan 。这说明SGD模型收敛到了最差的局部最优解。这种情况在步长较大的时候容易出现,原因是算法收敛太快而不能得到最优解。另外,小步长与相对较小的迭代次数(比如上面的10次)对应的训练模型性能一般较差。而较小的步长与较大的迭代次数下通常可以收敛得到较好的解。通常来讲,步长和迭代次数的设定需要权衡。较小的步长意味着收敛速度慢,需要较大的迭代次数。但是较大的迭代次数更加耗时,特别是在大数据集上。

  还可以调节L1正则化和L2正则化参数。 MLlib目前支持两种正则化方法L1和L2。 L2正则化假设模型参数服从高斯分布,L2正则化函数比L1更光滑,所以更容易计算;L1假设模型参数服从拉普拉斯分布,L1正则化具备产生稀疏解的功能,从而具备Feature Selection的能力。(由于spark 2.1.0中的线性回归方法已经忽略了,就没去验证L1和L2对模型的影响)

    

SparkMLlib学习之线性回归的更多相关文章

  1. SparkMLlib学习分类算法之逻辑回归算法

    SparkMLlib学习分类算法之逻辑回归算法 (一),逻辑回归算法的概念(参考网址:http://blog.csdn.net/sinat_33761963/article/details/51693 ...

  2. 【深度学习】线性回归(Linear Regression)——原理、均方损失、小批量随机梯度下降

    1. 线性回归 回归(regression)问题指一类为一个或多个自变量与因变量之间关系建模的方法,通常用来表示输入和输出之间的关系. 机器学习领域中多数问题都与预测相关,当我们想预测一个数值时,就会 ...

  3. [Machine Learning]学习笔记-线性回归

    模型 假定有i组输入输出数据.输入变量可以用\(x^i\)表示,输出变量可以用\(y^i\)表示,一对\(\{x^i,y^i\}\)名为训练样本(training example),它们的集合则名为训 ...

  4. 莫烦python教程学习笔记——线性回归模型的属性

    #调用查看线性回归的几个属性 # Youtube video tutorial: https://www.youtube.com/channel/UCdyjiB5H8Pu7aDTNVXTTpcg # ...

  5. keras学习简单线性回归【1】

    转自:https://morvanzhou.github.io/tutorials/machine-learning/keras/2-1-regressor/ 总的代码的过程就是: 1.导入模块+创建 ...

  6. Stanford机器学习笔记-6. 学习模型的评估和选择

    6. 学习模型的评估与选择 Content 6. 学习模型的评估与选择 6.1 如何调试学习算法 6.2 评估假设函数(Evaluating a hypothesis) 6.3 模型选择与训练/验证/ ...

  7. SparkMLlib分类算法之支持向量机

    SparkMLlib分类算法之支持向量机 (一),概念 支持向量机(support vector machine)是一种分类算法,通过寻求结构化风险最小来提高学习机泛化能力,实现经验风险和置信范围的最 ...

  8. 线性回归、Logistic回归、Softmax回归

    线性回归(Linear Regression) 什么是回归? 给定一些数据,{(x1,y1),(x2,y2)…(xn,yn) },x的值来预测y的值,通常地,y的值是连续的就是回归问题,y的值是离散的 ...

  9. 机器学习之路:python线性回归分类器 LogisticRegression SGDClassifier 进行良恶性肿瘤分类预测

    使用python3 学习了线性回归的api 分别使用逻辑斯蒂回归  和   随机参数估计回归 对良恶性肿瘤进行预测 我把数据集下载到了本地,可以来我的git下载源代码和数据集:https://gith ...

随机推荐

  1. 【 Android】自定义的AlertDialog中的EditText无法调用输入法问题解决

    1.问题描述: 在自定义的AlertDialog 中添加了EditText组件,但运行时怎么点EditText都无法调出软键盘: 2.原因分析: 一开始我以为EditText的focus属性没有设置好 ...

  2. SpringBoot-SpringMvc的Interceptor拦截器配置

    Interceptor拦截器实现对每一个用户请求处理前后的业务处理,比如我们需要对用户请求进行响应时间的记录,需要记录请求从开始到结束所耗的时间,这时我们就需要用到拦截器了 下面我们以记录请求处理时间 ...

  3. 理解C++中的头文件和源文件的作用【转】

    一.C++编译模式通常,在一个C++程序中,只包含两类文件--.cpp文件和.h文件.其中,.cpp文件被称作C++源文件,里面放的都是C++的源代码:而.h文件则被称作C++头文件,里面放的也是C+ ...

  4. android中全局异常捕捉

    android中全局异常捕捉 只要写代码就会有bug,但是我们要想办法收集到客户的bug.有第三方bugly或者友盟等可以收集.但是,android原生就提供了有关收集异常的api,所以我们来学习一下 ...

  5. 论.net平台的切身感触(惑)

    这篇博客只是作者客观看法,不喜勿喷,条条大路通罗马,路不同风景也不一样,接下来的路该怎么走? 简介:作者.net程序员一枚,工作已有四年,接触过.net平台winform,webform,mvc的开发 ...

  6. android参数传递的几种方法

    Intent Intent i=new Intent(当前Activity.this,目标Activity.class); 1.传单值 传入: i. i.putExtra("名称" ...

  7. 单片机下载芯片max232,ch340,pl2303,hl340与下载接线

    开发板上的下载口位置一般都有很多 340,232等芯片,这些芯片都是干嘛用的呢? 普及:TTL电平    : 二进制电平,+5V等价于逻辑"1",0V等价于逻辑"0&qu ...

  8. Nmap功能与常用命令

    Nmap功能与常用命令 其基本功能有三个,一是探测一组主机是否在线:其次是扫描主机端口,嗅探所提供的网络服务:还可以推断主机所用的操作系统. Nmap可用于扫描仅有两个节点的LAN,直至500个节点以 ...

  9. bzoj1013 [JSOI2008]球形空间产生器

    Description 有一个球形空间产生器能够在n维空间中产生一个坚硬的球体.现在,你被困在了这个n维球体中,你只知道球面上n+1个点的坐标,你需要以最快的速度确定这个n维球体的球心坐标,以便于摧毁 ...

  10. for循环之初学者N多算法小练习

    for循环之初学者N多算法小练习 显示1到100的数,每行显示5个. for (int i=1;i<=100;i++){     if (i%5==0){         System.out. ...