机器学习之线性回归

2020/11/20

概述

说起线性回归,首先要介绍一下机器学习中的两个常见的问题:回归任务和分类任务。那什么是回归任务和分类任务呢?简单的来说,在监督学习中(也就是有标签的数据中),标签值为连续值时是回归任务,标志值是离散值时是分类任务。而线性回归模型就是处理回归任务的最基础的模型。

前言

什么是线性回归,我们首先用弄清楚什么是线性,什么是非线性,还有回归到底是什么意思?

  • 线性:两个变量之间的关系是一次函数关系的——图象是直线,叫做线性。

    注意:题目的线性是指广义的线性,也就是数据与数据之间的关系。

  • 非线性:两个变量之间的关系不是一次函数关系的——图象不是直线,叫做非线性。
  • 回归:人们在测量事物的时候因为客观条件所限,求得的都是测量值,而不是事物真实的值,为了能够得到真实值,无限次的进行测量,最后通过这些测量数据计算回归到真实值,这就是回归的由来。

通俗的说就是用一个函数去逼近这个真实值,那又有人问了,线性回归不是用来做预测吗?是的,通过大量的数据我们是可以预测到真实值的。

线性回归可能是统计学和机器学习中最著名和最容易理解的算法之一。

预测建模主要关注的是最小化模型的误差,以牺牲可解释性为代价使最准确的预测成为可能。我们借鉴各种的领域的算法来处理统计数据以达到预测目的。

线性回归的表示是一个方程,它描述了一条线,通过寻找输入变量系数(B)的特定权重,拟合输入变量(x)和输出变量(y)之间的关系。

![](https://upload-images.jianshu.io/upload_images/1845730-21e6f9c6a51b5ab8.jpeg?imageMogr2/auto-orient/strip imageView2/2/w/690/format/webp)

例如:y=B0+B1*x

我们将在给定输入x的情况下预测y,线性回归学习算法的目标是找到系数B0和B1的值。 可以使用不同的技术从数据中学习线性回归模型,如普通最小二乘的线性代数解和梯度下降优化。

线性回归已经有200多年的历史了,并被广泛研究。在使用此技术时,一些很好的经验法则是删除非常相似(相关)的变量,并尽可能从数据中删除噪声。这是一种快速简单的技术,也是一种很好的算法。

应用

对大量的观测数据进行处理,从而得到比较符合事物内部规律的数学表达式。也就是说寻找到数据与数据之间的规律所在,从而就可以模拟出结果,也就是对结果进行预测。解决的就是通过已知的数据得到未知的结果。例如:对房价的预测、判断信用评价、电影票房预估等。

线性回归的一般模型

![](https://upload-images.jianshu.io/upload_images/1845730-840468295d690f6d.png?imageMogr2/auto-orient/strip imageView2/2/w/1200/format/webp)

大家看上面图片,图片上有很多个小点点,通过这些小点点我们很难预测当x值=某个值时,y的值是多少,我们无法得知,所以,数学家是很聪明的,是否能够找到一条直线来描述这些点的趋势或者分布呢?答案是肯定的。相信大家在学校的时候都学过这样的直线,只是当时不知道这个方程在现实中是可以用来预测很多事物的。

那么问题来了,什么是模型呢?先来看看下面这幅图。

![](https://upload-images.jianshu.io/upload_images/1845730-16bb6ad537c30d6a.png?imageMogr2/auto-orient/strip imageView2/2/w/747/format/webp)

假设数据就是x,结果是y,那中间的模型其实就是一个方程,这是一种片面的解释,但有助于我们去理解模型到底是个什么东西。以前在学校的时候总是不理解数学建模比赛到底在做些什么,现在理解了,是从题目给的数据中找到数据与数据之间的关系,建立数学方程模型,得到结果解决现实问题。其实是和机器学习中的模型是一样的意思。那么线性回归的一般模型是什么呢?

![](https://upload-images.jianshu.io/upload_images/1845730-f87f269014eff304.png?imageMogr2/auto-orient/strip imageView2/2/w/554/format/webp)

模型神秘的面纱已经被我们揭开了,就是以上这个公式,不要被公式吓到,只要知道模型长什么样就行了。假设i=0,表示的是一元一次方程,是穿过坐标系中原点的一条直线,以此类推。

如何使用模型

我们知道x是已知条件,通过公式求出y。已知条件其实就是我们的数据,以预测房价的案例来说明:

![](https://upload-images.jianshu.io/upload_images/1845730-4a262dde14d0b079.png?imageMogr2/auto-orient/strip imageView2/2/w/1005/format/webp)

上图给出的是某个地区房价的一些相关信息,有日期、房间数、建筑面积、房屋评分等特征,表里头的数据就是我们要的x1、x2、x3………. 自然的表中的price列就是房屋的价格,也就是y。现在需要求的就是theta的值了,后续步骤都需要依赖计算机来训练求解。

模型计算

当然,这些计算虽然复杂,但python库中有现成的函数直接调用就可以求解。我们为了理解内部的计算原理,就需要一步一步的来剖析计算过程。

为了容易理解模型,假设该模型是一元一次函数,我们把一组数据x和y带入模型中,会得到如下图所示线段。

![](https://upload-images.jianshu.io/upload_images/1845730-8f01c25f98b8584f.png?imageMogr2/auto-orient/strip imageView2/2/w/596/format/webp)

是不是觉得这条直线拟合得不够好?显然最好的效果应该是这条直线穿过所有的点才是,需要对模型进行优化,这里我们要引入一个概念。

损失函数:是用来估量你模型的预测值 f(x)与真实值 YY 的不一致程度,损失函数越小,模型的效果就越好。

求解线性回归模型的方法叫做最小二乘法,最小二乘法的核心就是保证所有数据偏差的平方和最小。它的具体形式是:

![](https://upload-images.jianshu.io/upload_images/1845730-d2bfa1ce0a6d2c90.png?imageMogr2/auto-orient/strip imageView2/2/w/813/format/webp)

其中hθ(x^(i))代表每个样本通过我们模型的预测值,y^(i)代表每个样本标签的真实值,m为样本个数。因为模型预测值和真实值间存在误差e,可以写作:

不要看公式很复杂,其实就是一句话,(预测值-真实值)的平法和的平均值,换句话说就是点到直线距离和最小。用一幅图来表示:

![](https://upload-images.jianshu.io/upload_images/1845730-7889ef24eaccb595.png?imageMogr2/auto-orient/strip imageView2/2/w/557/format/webp)

一开始损失函数是比较大的,但随着直线的不断变化(模型不断训练),损失函数会越来越小,从而达到极小值点,也就是我们要得到的最终模型。

这种方法我们统称为梯度下降法。随着模型的不断训练,损失函数的梯度越来越平,直至极小值点,点到直线的距离和最小,所以这条直线就会经过所有的点,这就是我们要求的模型(函数)。

以此类推,高维的线性回归模型也是一样的,利用梯度下降法优化模型,寻找极值点,这就是模型训练的过程。

过拟合与欠拟合(underfitting and overfitting)

在机器学习模型训练当中,模型的泛化能力越强,就越能说明这个模型表现很好。什么是模型的泛化能力?

模型的泛化能力:在机器学习的模型学习的过程中的概念,在它处于学习的过程中时模型没有遇见过的样本时候的表现。

模型的泛化能力直接导致了模型会过拟合与欠拟合的情况。让我们来看看一下情况:

![](https://upload-images.jianshu.io/upload_images/1845730-d65ad9c57d7cc2dd.png?imageMogr2/auto-orient/strip imageView2/2/w/469/format/webp)

我们的目标是要实现点到直线的平方和最小,那通过以上图示显然可以看出中间那幅图的拟合程度很好,最左边的情况属于欠拟合,最右边的情况属于过拟合。

  • 欠拟合:训练集的预测值,与训练集的真实值有不少的误差,称之为欠拟合。 _ 过拟合:训练集的预测值,完全贴合训练集的真实值,称之为过拟合。

欠拟合已经很明白了,就是误差比较大,而过拟合呢是训练集上表现得很好,换一批数据进行预测结果就很不理想了,泛化说的就是一个通用性。

解决方法

使用正则化项,也就是给梯度下降公式加上一个参数,即:

![](https://upload-images.jianshu.io/upload_images/1845730-a31d4ecc9c6a57e0.png?imageMogr2/auto-orient/strip imageView2/2/w/636/format/webp)

加入这个正则化项好处:

  1. 控制参数幅度,不让模型“无法无天”。
  2. 限制参数搜索空间
  3. 解决欠拟合与过拟合的问题。

看到这里是不是觉得很麻烦,我之前说过现在是解释线性回归模型的原理与优化,但是到了真正使用上这些方法是一句话的事,因为这些计算库别人已经准备好了,感谢开源吧!

实例

实例1 计算匹萨的价格

首先,我们从简单的一元线性回归问题开始。

假设你想计算匹萨的价格。虽然看看菜单就知道了,不过也可以用机器学习方法建一个线性回归模

型,通过分析匹萨的直径与价格的数据的线性关系,来预测任意直径匹萨的价格。我们先用scikit

learn写出回归模型,然后我们介绍模型的用法,以及将模型应用到具体问题中。假设我们查到了部

分匹萨的直径与价格的数据,这就构成了训练数据,如下表所示:

可行性分析

简单而直观的方式是通过数据的可视化直接观察匹萨价格与匹萨尺寸间是否存在线性关系。

对于本实验的数据来说,散点图就可以很好的将其在二维平面中进行可视化表示。

我们可以用matplotlib画出图形:

import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties
font = FontProperties(fname=r"c:\windows\fonts\msyh.ttc", size=8)

plt.title('匹萨价格与直径数据', fontproperties=font)
plt.xlabel('直径(英寸)', fontproperties=font)
plt.ylabel('价格(美元)', fontproperties=font)
plt.axis([0, 25, 0, 25])
plt.grid(True)
X = [[6], [8], [10], [14], [18]]
y = [[7], [9], [13], [17.5], [18]]
plt.plot(X, y, 'k.')
plt.show()

输出结果如下:

上图中,’x’轴表示匹萨直径,’y’轴表示匹萨价格。能够看出,匹萨价格与其直径正相关,这与我们的

日常经验也比较吻合,自然是越大越贵。下面我们就用scikit-learn来构建模型。

from sklearn import linear_model        #表示,可以调用sklearn中的linear_model模块进行线性回归。
import numpy as np
model = linear_model.LinearRegression()
model.fit(X, y)
print(model.intercept_)  #截距
print(model.coef_)  #线性模型的系数
a = model.predict([[12]])
# a[0][0]
print("预测一张12英寸匹萨价格:{:.2f}".format(model.predict([[12]])[0][0]))

输出结果如下:

[1.96551724] [[0.9762931]] 预测一张12英寸匹萨价格:13.68

调用sklearn.linear_model.LinearRegression()所需参数:

  • fit_intercept : 布尔型参数,表示是否计算该模型截距。可选参数。
  • normalize : 布尔型参数,若为True,则X在回归前进行归一化。可选参数。默认值为False。
  • copy_X : 布尔型参数,若为True,则X将被复制;否则将被覆盖。 可选参数。默认值为True。
  • n_jobs : 整型参数,表示用于计算的作业数量;若为-1,则用所有的CPU。可选参数。默认值为1。

线性回归fit函数用于拟合输入输出数据,调用形式为model.fit(X,y, sample_weight=None):

  • X : X为训练向量;
  • y : y为相对于X的目标向量;
  • sample_weight : 分配给各个样本的权重数组,一般不需要使用,可省略。

注意:X,y 以及model.fit()返回的值都是2-D数组,如:a= [ [ 0] ]

一元线性回归假设解释变量和响应变量之间存在线性关系;这个线性模型所构成的空间是一个超平面(hyperplane)超平面是n维欧氏空间中余维度等于一的线性子空间,如平面中的直线、空间中的平面等,总比包含它的空间少一维。在一元线性回归中,一个维度是响应变量,另一个维度是解释变量,总共两维。因此,其超平面只有一维,就是一条线。

上述代码中sklearn.linear_model.LinearRegression类是一个估计器(estimator)估计器依据观测值来预测结果。在scikit-learn里面,所有的估计器都带有fit()predict()方法。fit()用来分析模型参数,predict()是通过fit()算出的模型参数构成的模型,对解释变量进行预测获得的值。因为所有的估计器都有这两种方法,所有scikit-learn很容易实验不同的模型。

LinearRegression类的fit()方法学习下面的一元线性回归模型:y=α+βx

y表示响应变量的预测值,本例指匹萨价格预测值, x是解释变量,本例指匹萨直径。截距α和系数β 是线性回归模型最关心的事情。下图中的直线就是匹萨直径与价格的线性关系。用这个模型,你可以计算不同直径的价格,如8英寸$7.33,20英寸$18.75。

plt = runplt()
plt.plot(X, y, 'k.')
X2 = [[0], [10], [14], [25]]
model = linear_model.LinearRegression()
model.fit(X,y)
y2 = model.predict(X2)
plt.plot(X2, y2, 'g-')
plt.show()

一元线性回归拟合模型的参数估计常用方法是普通最小二乘法(ordinary least squares )或线性最小二乘法(linear least squares)。首先,我们定义出拟合成本函数,然后对参数进行数理统计。

带成本函数的模型拟合评估

下图是由若干参数生成的回归直线。如何判断哪一条直线才是最佳拟合呢?

plt = runplt(size=(10,10))
plt.plot(X, y, 'k.')
y3 = [14.25, 14.25, 14.25, 14.25]
y4 = y2*0.5 + 5
model.fit(X[1:-1], y[1:-1])
y5 = model.predict(X2)
plt.plot(X, y, 'k.', label="X, y") 
plt.plot(X2, y2, 'g-.', label="X2 y2")
plt.plot(X2, y3, 'r-.',label="X2, y3")
plt.plot(X2, y4, 'y-.',label="X2, y4")
plt.plot(X2, y5, 'o-', label="X2, y5")
plt.legend()
plt.show()

成本函数(cost function)也叫损失函数(loss function),用来定义模型与观测值的误差。模型预

测的价格与训练集数据的差异称为残差(residuals)或训练误差(training errors)。后面我们会用

模型计算测试集,那时模型预测的价格与测试集数据的差异称为预测误差(prediction errors)或测试误差(test errors)。

  • 近似误差:可以理解为对现有训练集的训练误差。
  • 估计误差:可以理解为对测试集的测试误差。

模型的残差是训练样本点与线性回归模型的纵向距离,如下所示

plt = runplt()
plt.plot(X, y, 'k.')
X2 = [[0], [10], [14], [25]]
model = linear_model.LinearRegression()
model.fit(X, y)
y2 = model.predict(X2)
plt.plot(X, y, 'k.')
plt.plot(X2, y2, 'g-')

# 残差预测值
yr = model.predict(X)
#  enumerate 函数可以把一个 list 变成索引-元素对
for idx, x in enumerate(X):
    plt.plot([x, x], [y[idx], yr[idx]], 'r-')
plt.show()

我们可以通过残差之和最小化实现最佳拟合,也就是说模型预测的值与训练集的数据最接近就是最佳拟合。对模型的拟合度进行评估的函数称为残差平方和(residual sum of squares)成本函数。就是让所有训练数据与模型的残差的平方之和最小化,残差平方和计算如下:

import numpy as np
print('残差平方和:{:.2f}'.format(np.mean((model.predict(X) - y) ** 2)))

输出结果如下:

残差平方和:1.75

有了成本函数,就要使其最小化获得参数。

参考网址

https://www.jianshu.com/p/7c3cdddb6843

目录