JavaEE鸿蒙应用开发HTML&JS+前端Python+大数据开发人工智能开发电商视觉设计软件测试新媒体+短视频直播运营产品经理集成电路应用开发(含嵌入式)Linux云计算+运维开发C/C++拍摄剪辑+短视频制作PMP项目管理认证电商运营Go语言与区块链大数据PHP工程师Android+物联网iOS.NET

SparkMllib如何解决回归问题?

来源:黑马程序员

浏览4873人

2019.09.19

1-问题引入

我们都参加过高考,据统计,高考的物理成绩确实与数学成绩有一定关系,但除此之外,还存在很多影响物理成绩的因素,例如:是否喜欢物理,用在物理上的时间等。而当我们主要考虑数学成绩对物理的影响时,就是要考察这两者之间的相关关系。

现实生活中还有很多的相关关系,如

1.商品销售输入与广告支出经费之间的关系,销售输入与广告支出有着密切的关系,但是还与商品质量、居民收入等因素有关。

2.粮食产量与施肥量之间的关系。在一定范围内,施肥量越大,粮食生产就越高。除此之外,粮食产量还受到土壤质量、降雨量等的影响。

3.人体内脂肪的含量与年龄之间的关系。在一定年龄段内,随着年龄的增长,人体内的脂肪含量会增加,但人体内的脂肪含量还和饮食习惯,体育锻炼有关系,可能还与先天

体质有关系。

对于上述两个变量之间的关系,应该说都可以根据经验做出相应的判断,因为“经验当中有规律”,但是,不管你经验多么丰富,如果只凭借经验办事,还是很容易出错。因此在分析两个变量之间的相关关系时,我们需要一些说服力的办法。

在寻找变量之间的相关关系中,统计同样发挥着非常重要的作用。因为上面提到的这种关系,并不像匀速直线运动中时间与速度的关系那样是完全确定的,而是带有不确定性,这就需要通过收集大量的数据(有时候通过调查、或实验),在对数据进行统计分析的基础上,发现其中的规律,才能让他们之间的关系做出判断。

2-脂肪含量和年龄相关吗?

两个变量的线性相关:

如下表中描述了人体的脂肪百分比和年龄的关系图表:

年龄脂肪含量

239.5

2717.8

3921.2

4125.9

4527.5

4926.3

5028.2

5329.6

5430.2

5631.4

5730.8

5833.5

6035.2

6134.6

问题:根据上述数据,人体的脂肪含量与年龄之间有怎么样的关系呢?

对问题的描述:

一般地,对于某个人来说,他的体内脂肪不一定随年龄增长而增加或减少,但是如果把很多个体放在一起,这时就可能表现出一定的规律性,各年龄对应的脂肪数据是这个年龄人群脂肪含量的样本平均值。观察上述表数据,从大体上看,随着年龄的增加,人体中脂肪的百分比也在增加。为了确定这一细节,我们需要进行数据的分析,与以前一样,我们可以做统计图、表,通过作统计图、表,可以使我们对两个变量之间的关系有一个直观的印象和判断。

下面我们做一个散点图,如图,假设人的年龄影响体内脂肪含量,于是,按照习惯,以x轴表示年龄,y轴表示脂肪含量,得到下图:

1568877598106912.png 

这些散分布的位置也是值得注意的,他们散布在从左上角到右下角的区域。对于两个变量的这种相关关系,我们称为正相关。还有一些变量,例如汽车的重量和汽车每消耗1L汽油所行驶的平均路程,是负相关,也就是汽车越重,每消耗1L汽油所行驶的平均路程就越短,这时的点如果绘制在画布上 将会从左上角到右下角的区域内。

接下来,需要进一步考虑的问题是,当人的年龄增加时,体内脂肪含量到底是以什么方式增加的呢?

 1568877610542200.png


从散点图可以看出,这些点大致分布在通过散点图中心的一条直线附近,如果散点图中的点分布从整体上看大致是在一条直线附近,我们就称这两个变量之间具有线性相关关系,这条直线叫做回归直线(regression line)。

如果能求出这条回归直线的方程,那么我们就可以清晰的了解年龄与体内脂肪含量的相关性,就像平均值可以作为一个变量的数据的代表一样,这条直线可以作为两个变量具有线性相关性的代表。

1568877623845445.png 

当你拿到这样一个任务的时候,你可能会采用测量的做法,先画出一条直线,测量各点与它的距离,然后移动直线,到达一个使得距离的和最小的位置,测量出此时的斜率和截距,既可以得到回归方程了。

也可能会采用平均方法,也就是在散点图中多取几组点,确定出几条直线的方程,在分别求出各条直线的斜率、截距的平均数,将这两个平均数作为回归方程的斜率和截距。

3-问题的求解

上面方法虽然有一定道理,但是总让人感觉可靠性不强。实际上,求回归方程的关键是如何用数学的方法来刻画“从整体上,各点与此直线的距离最小”。

假设我们已经得到两个具有线性相关关系的变量的一组数据

 1568877715615956.png

且所求的回归方程设为

 1568877725809341.png

它与实际数据的偏差是

 1568877734115350.png

在坐标轴中表示如下

1568877747140985.png 

这样,用这n个偏差的和来刻画“各点与此直线的整体偏差”比较合适的,由于 1568877762102609.png可正可负,为了避免互相抵消,可以考虑用1568877779912273.png代替,但由于它含有绝对这,运算不方便,所以改用1568877800134766.png

即:

 1568877815105294.png

这样,问题就归结为:当a和b取什么值时Q最小,即总体偏差最小,经过数学上的最小值运算,a和b的值由下面式子给出

1568877826116284.png

其中b是回归方程的斜率,a是截距。

总结:这种通过求解Q关系式的最小值而得到回归直线的方法,即求回归直线,使得样本数据的点到它的距离的平方和最小的方法,叫做最小二乘法(Least square)。

4-Execl绘制相关图形

Execl画回归拟合直线如下方法:

(1)准备数据,首先绘制散点图

(2)在散点图基础上点”趋势预测”即可看到拟合的直线。

 1568877853711960.png

(3)在图示区域显示拟合直线的方程

 1568877863126164.png

5-SparkMl代码实战

这里采用基于DataFrame的SparkMl完成实验,并与Execl的结果进行对比分析:

代码部分:

import org.apache.spark.ml.linalg.Vectors

import org.apache.spark.ml.regression.{LinearRegression, LinearRegressionModel}

import org.apache.spark.sql.SparkSession

object testFat {

  def main(args: Array[String]): Unit = {

  val spark: SparkSession = SparkSession.builder().master("local[*]").appName("traintestSplitTest").getOrCreate()

    spark.sparkContext.setLogLevel("WARN")

    val data = spark.createDataFrame(Seq(

      (9.5, Vectors.dense(23)),

      (17.8, Vectors.dense(27)),

      (21.2, Vectors.dense(39)),

      (25.9, Vectors.dense(41)),

      (27.5, Vectors.dense(45)),

      (26.3, Vectors.dense(49)),

      (28.2, Vectors.dense(50)),

      (29.6, Vectors.dense(53)),

      (30.2, Vectors.dense(54)),

      (31.4, Vectors.dense(56)),

      (30.8, Vectors.dense(57)),

      (33.5, Vectors.dense(58)),

      (35.2, Vectors.dense(60)),

      (34.6, Vectors.dense(61))

    )).toDF("label", "features")

    //1-data split

    val Array(train, test): Array[Dataset[Row]] = data.randomSplit(Array(0.9, 0.1), seed = 120L)

    //2-training model

    val lr: LinearRegression = new LinearRegression()

    val lrModel: LinearRegressionModel = lr.fit(data)

    //3- Print the coefficients and intercept for linear regression

    println(s"Coefficients: ${lrModel.coefficients} Intercept: ${lrModel.intercept}")

    // 4-Summarize the model over the training set and print out some metrics

    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}")

    //    Coefficients: [0.5764772505370067] Intercept: -0.44779925795753567

    //    numIterations: 1

    //    objectiveHistory: [0.0]

    //    +---------------------------------------------+

    //    |           residuals|

    //    +--------------------------------------------+

    //    |  -3.311177504393619|

    //    |   2.682913493458356|

    //    .............................

    //    RMSE: 1.629890205389517

    //    r2: 0.9423379190667397

  }

}

这里得到的R2是回归问题的考量标准,越接近于1效果越好,这里r2为0.94效果能够达到预期,因此能够证明随着年龄的增长脂肪含量会随着增长,在回归问题中此类问题常称之为一元线性回归或简单线性回归,当然可以考虑更多的变量因素存在对脂肪含量的影响,这里不再一一列举。

6-总结

通过对脂肪含量和年龄的关系问题猜想、定义、Execl绘图分析、SparkMl建模分析得到我们猜测和数学上可证明的结论,同学们可以借助SparkMl技术解决更多的回归问题。加油!