Chapter2 SparkMLlib回归算法详解
2.SparkMLlib回归算法
2.1 SparkMLlib线性回归算法
2.1.1 线性回归算法
线性回归Linear Regression利用最小均方函数对一个或多个自变量和因变量之间的关系进行建模并分析。这种函数是线性回归方程,是一个或多个由回归系数作为模型参数的线性组合。在这种回归分析中,分为一元线性回归分析和多元线性回归分析,一元是指只包括一个自变量和一个因变量,且二者关系能用一条直线近似,二元是指包括两个或两个以上的自变量,且与因变量之间是线性关系。
而两种分析都可以用下面的形式统一表示:
就是回归系数等式最后表示回归系数矩阵与矩阵相乘,我们的目标就是求取这个回归系数矩阵。
在此我们如下的损失函数去评估所求的回归系数是否最优,也就是描述我们预测的结果有多好:
损失函数是预测值与真实值之差的平方和, 的系数是为了后续求导的方便。现在的目标就是寻找使得损失函数最小的回归系数。常用的方法有梯度下降法和最小二乘法。同时,回归分析中也常常会存在过拟合的问题,这是由于训练样本过于侧重某些点,训练得到的曲线对待测样本数据的预测精度会下降,即拟合程度不够。通常的做法是对数据进行正则化处理。其基本思想是防止由拟合算法得到的回归公式对某些特定的特征值更加敏感,对增加的系数使其系数为零进行消除从而消除过拟合。
2.1.2算法源码分析
MLlib中用随机梯度下降算法优化损失函数,梯度下降的意义就是,用损失函数对参数求偏导数,也就是梯度,沿着梯度方向,损失函数减小的最快,当达到收敛时,也就求到了最优的参数。此处的随机梯度下降方法是:进行多轮迭代计算,每一次随机抽取一定样本进行计算;对所计算的每一个样本计算梯度;再将样本梯度进行累加,求得平均梯度和损失;最后根据这次的梯度和上一次迭代的权重对梯度和权重进行更新。
实现过程如下:
(1)建立线性回归模型
建立模型的入口是线性回归伴生对象LinearRegressionWithSGD,定义了训练模型的train方法,设置训练参数进行模型训练,主要参数如下:
*Input——标签和特征序列组成的RDD训练样本,每对有一列数据和其对应的标签;
*numiterations——要运行的渐变下降迭代次数,默认100;
*step size——步进大小,用于每次梯度下降迭代,默认1;
*minibatchfraction——每次迭代使用的样本比例,默认1,即全部样本
*weights要使用的初始权重集,数组的大小应等于数据中的特征数量。
线性回归类LinearRegressionWithSGD是基于梯度下降法生成线性回归模型,完成了初始化梯度下降、梯度更新、优化计算等功能,根据初始化的方法调用集成了广义回归类GeneralizedLinearAlgorithm的run方法训练模型。
(2)run方法训练模型
此方法首先对样本加偏置,然后进行初始化权重,调用optimizer.optimize方法进行权重优化,最后获取最优权重。
(3)权重优化
optimizer.optimize方法是调用了GradientDescent伴生对象的runMiniBatchSGD方法来实现最终梯度下降算法的实现,通过迭代计算样本的梯度及误差返回最优梯度和误差。而gradient.compute基于最小二乘法完成了每个样本的梯度及误差计算。最后使用updata.compute进行权重更新。
(4)模型生成
模型训练完成后,生成线性回归模型类,参数包含:各个特征的权重向量及偏置,可以完成预测、保存模型、加载模型等方法。
2.1.3应用实战
(1)数据说明
以下是根据一个应用LinearRegression进行数据处理的实例,用到的训练数据格式如下:
-9.490009878824548 1:0.4551273600657362 2:0.36644694351969087 3:-0.38256108933468047 4:-0.4458430198517267 5:0.33109790358914726 6:0.8067445293443565 7:-0.2624341731773887 8:-0.44850386111659524 9:-0.07269284838169332 10:0.5658035575800715
第一个是数据的标签,“:”前的数字是特征的维数序号,后边的数字是具体的特征值,一共是十维。本例的目标是根据训练数据训练一个正则化的线性模型,并且提取一些模型的概要统计量。
(2)代码详解
第一步是导入MLlib中线性模型的API:
import org.apache.spark.ml.regression.LinearRegression
第二步加载我们上文中所述的训练数据:
val training = spark.read.format("libsvm")
.load("/mnt/hgfs/thunderdownload/MLlib_rep/data/sample_linear_regression_data.txt")
第三步是设置模型的参数:
val lr = new LinearRegression().setMaxIter(10).setRegParam(0.3)
.setElasticNetParam(0.8)
第四步是将数据输入设置好的模型:
val lrModel = lr.fit(training)
第五步就是输出根据训练数据得到的线性模型的回归系数和截距:
println(s"Coefficients: ${lrModel.coefficients} Intercept: ${lrModel.intercept}")
输出结果如下:
最后就是概括模型在训练集上的表现,并且打印出模型的训练结果参数:
val trainingSummary = lrModel.summary
//模型的迭代次数
println(s"numIterations: ${trainingSummary.totalIterations}")
//每次迭代的目标函数的结果,即标度损失+正则化
println(s"objectiveHistory: [${trainingSummary.objectiveHistory.mkString(",")}]")
//输出预测标签值的残差
trainingSummary.residuals.show()
//输出均方根误差和相关系数,数值越小,预测模型对实验数据的预测精度更高
println(s"RMSE: ${trainingSummary.rootMeanSquaredError}")
println(s"r2: ${trainingSummary.r2}")