对于非线性回归的前提条件曲线,在何种情况下可以转化为直线的回归分析?

回归是一种解题方法,或者说“学习”方法,也是机器学习中比较重要的概念。没有学过回归的朋友可能看到回归这个词猜不出这是个什么概念,觉得很神秘。其实我平生第一次看到这个词的时候也猜不出是干什么用的,“回归?……回哪儿去?”。回归的英文是Regression,单词原型的regress大概的意思是“回退,退化,倒退”。其实Regression——回归分析的意思借用了“倒退,倒推”的含义。简单说就是“由果索因”的过程,是一种归纳的思想——当看到大量的事实所呈现的样态,推断出原因是如何的;当看到大量的数字对(pair)是某种样态,推断出它们之间蕴含的关系是如何的。8.1 线性回归线性回归是利用数理统计学中的回归分析来确定两种或两种以上变量间相互依赖的定量关系的一种统计分析方法。其表达形式如下:y=a x+b+ee 为误差服从均值为0的正态分布。简单说大概是这样,通过统计或者实验,可能会得到两种值(两个系列的值)的对应关系,这两种值一种是 y 一种是 x ,每组 y 和 x 是成对出现的一一对应,最后可以用一种 y=a x+b+e 的表达式来表示它们的关系。而这其中的 e 不是一个定值,它和 y 、x 对应着出现(有一对 y 和 x ,就有一个 e )。这个 e 的值满足正态分布,\mu 为0。有人说还是 y=ax+b 看着比较舒服,a 是斜率,b 是截距,初中时大家都学过。但是 y=a x+b+e 看着别扭,我们后面来说说这个e是怎么出来的。下面看一个完整的操作过程。8.2 拟合回归这种方法我们在中学课本里是没有讲过的,但是他的思想我们可是早在高中一年级的时候物理课上就学过的,只是我们没意识到。回忆一下,还记得高中的时候学过一个用打点计时器计算重力加速度g的大小的实验吗?将一个小铁球用一根线拴在一个很轻的小车上,小车后面拉着一根长长的有毫米刻度的纸带,一个打点计时器一边电源接着220V 50Hz的市电,有一根圆珠笔尖悬在纸带上方,如图8-1所示。图8-1 用打点计时器计算重力加速度当接通电源后,小铁球由于重力作用开始做自由落体的运动,同时拉着小车越跑越快,后面纸带上圆珠笔尖会以每秒50次的速度不停打点,这样在纸带上留下许多的点,每个点之间的距离会越来越大,每个相邻点之间的打点时间差为0.02s,如图8-2所示。图8-2 打出的点这个实验的先决条件是牛顿第二定律:F=m aF 是物体受到的外力大小,m 是物体的质量,a 是产生的加速度。由于在重力的作用下,所以G=m gG 是物体所受重力,m 是物体质量,g 是重力加速度,也就是要求的值。
我们现在手里得到什么了?是一个位移的记录,即纸带。在处理数据的时候我们用了一个技巧,即计算每个点之间的间隔\Delta s_{0}, \Delta s_{1}, \Delta s_{2}, \Delta s_{3}, \cdotss0 就是 t0 和 t1 两个时刻所打点的位移差距。位移 s 和时间 t 的关系是什么呢?我们都知道:s=v t速度乘以时间就是位移,比如我骑自行车一秒钟跑10米,那10秒钟就跑100米,这个对于匀速运动肯定没错。v=f(t) 示意图如图8-3所示,横坐标轴为 t ,纵坐标轴为 v 。当然只有 t 大于0的部分是有意义的,如果想知道当 t=30 时,s 为多少,只需要在 t=30 的位置把这个图形切开,求 t 为从0到30,v=10 的长方形面积即可(s=vt)。图8-3 匀速直线运动如果运动速度是不均匀的怎么办呢?可以用积分的方法:s=\int v(t) \cdot \mathrm{dt}其中 v(t) 是一个 v=f(t) 的函数,是一个变化的 v 和对应时间t的关系,后面的 \mathrm{dt} 是 \Delta \mathrm{t} 的概念,也会有人习惯地写成这种形式:s(t)=\int_{0}^{t} v(x) \cdot \mathrm{d} \mathrm{x}整个积分式的含义就是位移 s 是一个随着 t 变化的函数,而整个过程中 s 是由这一刻瞬间的速度 v(t) 和瞬间的时间长度 \mathrm{dt}(\Delta \mathrm{t}) 相乘而来的。听起来好像是所有的值都在变化很难把握,读者先别慌神,往下看。在这里先讲一个小故事。德国著名的教学家、物理学家波恩哈德·黎曼图8-4发明了一种很有名的丈量方法——“黎曼和”。这个思想很简单,大概如下。图8-4 波恩哈德·黎曼要求一块不规则形状的土地的面积,怎么办?把它划分成很多小长方形,每个小长方形的面积都可以比较容易用长乘以宽的方式求出来,然后再加到一起,就能算出整个不规则土地的面积了。这里有误差怎么办?可以尽量把长方形画窄一些,越窄,面积和越逼近“真实”的土地面积,只要这个误差到达允许的范围内,那这个面积和基本就是所要求的面积,如图8-5所示。这个方法可不土,人家实际上用的可是正经是微积分的思想哟。图8-5 黎曼和示意图再回到刚刚的问题 s=vt ,这其实也是一个面积公式,t 是宽度,v 是高度,只是 v 这个高度是变化的。匀速的时候 v 是一个定值,算出来是一个长方形面积,这就是一个黎曼和求和的过程。另外,有公式v=v_{0}+g t其中由于一开始小球和车是静止的,所以v0=0是知道的。那么v=g t成立,而且有s=\frac{1}{2} g t^{2}这样求位移的方法成了求三角形面积的方法了。如图8-6所示,10s、20s、30s、40s、50s时所产生的位移就是此时的t刻度纵线与t轴以及函数曲线 \mathrm{v}=\mathrm{v}_{0}+\mathrm{gt} 所围成的面积。图8-6所为 \mathrm{v}=\mathrm{v}_{0}+\mathrm{gt} 函数图线,当然,也只是 t 大于零的部分才有效。\begin{aligned}
\Delta s_{0} &=s_{1}-s_{0} \\
&=(1 / 2) \times g \times\left(v_{0}+g t_{1}\right) \times t_{1}-(1 / 2) \times g \times\left(v_{0}+g t_{0}\right) \times t_{0} \\
&=(1 / 2) \times g \times\left(t_{1}^{2}-t_{0}^{2}\right) \\
&=(1 / 2) \times g \times\left(t_{1}+t_{0}\right)\left(\mathrm{t}_{1}-t_{0}\right) \\
&=(1 / 2) \times g \times \Delta t \times\left(t_{1}+t_{0}\right)
\end{aligned}其中 \Delta t 就是0.02s,指的是每次打点的间隔。图8-6 v=v0+gt函数图线以此类推\begin{aligned}
\Delta s_{1} &=s_{2}-s_{1} \\
&=(1 / 2) \times g \times \Delta t \times\left(t_{2}+t_{1}\right) \\
\Delta s_{2} &=s_{3}-s_{2} \\
&=(1 / 2) \times g \times \Delta t \times\left(t_{3}+t_{2}\right) \\
& \cdots \\
\Delta s_{n} &=S_{n+1}-S_{n} \\
&=(1 / 2) \times g \times \Delta t \times\left(t_{n+1}+t_{n}\right)
\end{aligned}也就是说,每两个临近的点之间的距离都可以用这个公式来套算,因为这个公式本身就是计算位移差的公式。如果把临近的位移差做减法会得到什么呢?\begin{aligned}
\Delta s_{1}-\Delta s_{0} &=(1 / 2) \times g \times \Delta t \times\left(t_{2}+t_{1}\right)-(1 / 2) \times g \times \Delta t \times\left(t_{1}+t_{0}\right) \\
&=(1 / 2) \times g \times \Delta t \times\left(t_{2}-t_{0}\right) \\
&=g \Delta t^{2} \\
\Delta s_{2}-\Delta s_{1} &=(1 / 2) \times g \times \Delta t \times\left(t_{3}+t_{2}\right)-(1 / 2) \times g \times \Delta t \times\left(t_{2}+t_{1}\right) \\
&=(1 / 2) \times g \times \Delta t \times\left(t_{3}-t_{1}\right) \\
&=g \Delta t^{2}
\end{aligned}所有临近的两个点之间的距离之差为一个确定的数字,就是 \mathrm{g} \Delta \mathrm{t}^{2} ,g 和 \Delta \mathrm{t} 都是定值,只是现在还假装不知道 g 的具体大小。那下面也就更好办了,把每个临近的距离差都列出来,平均一下就能得到 \mathrm{g} \Delta \mathrm{t} 的大小,再除以 \Delta \mathrm{t},就可以得到 g 。请注意,这个例子和教科书上讲的用“逐差法”求加速度的细节有点区别,教科书上是把临近的6个点的差作为一个单位求差的,这主要是为了尽可能减小误差。还可以用v-t图法进行绘图。有瞬时速度公式v=v_{0}+g t=g t其实也就是v_{n}=g t_{n}尝试一下能不能从最直观量取到的位移s的差值得到和v有关的公式描述:\begin{aligned}
\Delta s_{1}+\Delta s_{0} &=(1 / 2) \times g \times \Delta t \times\left(t_{2}+t_{1}\right)+(1 / 2) \times g \times \Delta t \times\left(t_{1}+t_{0}\right) \\
&=(1 / 2) \times g \times \Delta t \times\left(t_{2}+t_{1}+t_{1}+t_{0}\right) \\
&=(1 / 2) \times g \times \Delta t \times\left(\Delta t+t_{1}+t_{1}+t_{1}+t_{1}-\Delta t\right) \\
&=(1 / 2) \times g \times 4 \times \Delta t \times t_{1} \\
&=2 \times g \times \Delta t \times t_{1}
\end{aligned}类推一下:\begin{array}{r}
\Delta s_{n}+\Delta s_{n-1}=2 \times g \times \Delta t \times t_{n} \\
\left(\Delta s_{n}+\Delta s_{n-1}\right) / 2 \Delta t=g \times t_{n}=v_{n}
\end{array}这里的 v_{n} 也就表示第 n 个0.02s的瞬时速度可以直接通过测量位移差求出来,从 v_{n} 上是可以直接得到 n 和 v 的对应关系的。如图8-7所示,在坐标纸上画一条直线穿过这些点。图8-7 v和t的关系示意图图8-7中的散点用一条直线连接,就可以得到一个比较粗糙的 v=g t的函数,斜率就是 g ,直接测量即可得出。这种从大量的函数结果和自变量反推回函数表达式的过程就是回归。刚才用的是划线穿点的方法来求一个粗略的 v=gt 。这种思路本身就是使用线性回归的方法。假设最后得到的数值如表8-1所示。表8-1 n和vn的数值试着用Python编程,用线性回归的方法实现这个例子:import numpy as np
import matplotlib.pyplot as plt
# 原始数据
x = [1, 2, 3, 4, 5, 6, 7, 8, 9]
y = [0.199, 0.389, 0.580, 0.783, 0.980, 1.177, 1.380, 1.575, 1.771]
A = np.vstack([x, np.ones(len(x))]).T
# A:
#[[ 1.
1.]
# [ 2.
1.]
# [ 3.
1.]
# [ 4.
1.]
# [ 5.
1.]
# [ 6.
1.]
# [ 7.
1.]
# [ 8.
1.]
# [ 9.
1.]]
# 调用最小二乘法函数
a, b = np.linalg.lstsq(A, y)[0]
# 转换成numpy array
x = np.array(x)
y = np.array(y)
# 画图
plt.plot(x, y, 'o', label='Original data', markersize=10)
plt.plot(x, a * x + b, 'r', label='Fitted line')
plt.show()
画出的图形如图8-8所示。回归在数据挖掘算法里也有着举足轻重的地位,在R语言里,在Mahout等开源数据挖掘框架里都有比较好的支持。如果读者有兴趣,可以再找R语言的环境或者Mahout做一下实验。刚刚在打点计时器的实验里用直线穿过众多散点的方式可以得到一个比较粗糙的 v=gt 的函数。说它粗糙的原因很简单,因为这条线是根据打点记录的位移来画的,小车轮子是否光滑,小车自重是不是比较大,市电是不是标准的50Hz,以及空气阻力大小如何等因素都会影响打点的准确性。这些因素也会导致 n 和 v_{n} 的比率在每个打点瞬间记录的不稳定,或比理想值大或比理想值小。而且在画这条直线穿过这些点时也可能会画不准,可能会有几种画法,每种画法在手法上略有偏差而画出来都能从中间穿过去,且都不能算错。不只在这个例子里,再换任何一个场景,通过统计或实验产生的这样一组对应关系同样都会有类似的问题。图8-8 画出的图形这种把平面上一系列的点用一条光滑的曲线连接起来的过程就叫做拟合——刚刚用一条函数曲线 v=g t 来进行了拟合。而多种拟合方法究竟哪一种画法最科学呢?下面将介绍分析的方法,即残差分析。8.3 残差分析刚刚已经尝试着做过拟合这个过程了,在前面提到过,在线性回归中希望最终得到一个函数 y=ax+b+e 来表示 y 和 x 的关系。从前面的打点计时器的例子来看,从理论上推定v=gt,而在实验中产生的其实是一个不太准确的函数 v=gt+e ,这里面没有 b\left(v_{0}\right) 这一项是因为 v_{0} 是 0 。那问题就转化为,g 究竟取多少才能让 e 最小呢?这个过程就是残差分析,而最终得到的结果就是要计算出一个 g ,使得 e 为误差服从均值为 0 的正态分布。定性地说就是在拟合的过程中,每一个点所产生的误差 e 大部分在 0 附近,而越远离 0 误差的 e 越少越好。有一种非常经典的用来进行线性回归中的系数猜测的方法——最小二乘法。推导过程对于没有学过微积分的读者可能会比较复杂,下面只简单介绍原理。假设有多个 x 和 y 的样本值,同时尝试用 y=ax+b+e 来拟合,可以得到|\mathrm{e}|=|a x+b-y|也就是说误差大小其实是猜想的 ax+b 的值和观测到的 y 值之间的差值。试着把所有的
e
都求和。构造一个函数:Q=\sum_{i=1}^{n}\left(a x_{i}+b-y_{i}\right)^{2}Q 指根据每一组样本里的 x 拟合得到的 y (也就是 ax+b )和观察到的样本里的 y 都做一个差,把差平方后求和。Q 就是每一个
e|^{2} 的和,现在的问题转化为让 a 和 b 分别等于什么值时 Q 最小(也就是所有的
e
的加和最小)。即\frac{\partial Q}{\partial a}=0且\frac{\partial Q}{\partial b}=0这两个表达式的数学含义是,Q 是一个 a 和 b 作为自变量的二元函数,Q 分别对 a 和 b 求偏微分,满足每个偏微分方程为 0 的 a 、 b 变量的值就是要找的值。如二元一次方程组y=a x^{2}+b x+c经过变换,y=\left[\left(x+\frac{b}{2 a}\right)^{2}+\frac{4 a c-b^{2}}{4 a^{2}}\right]y 的极值为 x=b/2a 时的值。这里面其实没有用到高等数学里求导数的概念,只是用了算数平方和大于等于零的性质来确定极值的位置,当平方项为 0 时,y 一定是极值,有y=\frac{4 a c-b^{2}}{4 a^{2}}\frac{\partial Q}{\partial a} 表示函数 Q 对自变量a求导,它的结果又是一个函数,而这个新函数称为导函数,简称导数。一般来说,导数里面还是会由 a 作为自变量的,而导数的函数值就是 Q 这个函数在a点上的切线斜率(本例不考虑不可导的情况)。可以想象,Q 是一个曲线函数,既然是曲线,在每个点上就有切线,让切线随着 Q 函数的曲线滑动,切线的斜率也会跟着变化,而 Q 函数的极值应该在切线斜率为 0 外,如这个例子中的极限值位置。切线应该是一条水平线。如图8-9所示,AB 直线从左向右紧贴着 y=x^{2} 曲线滑动,让切点一直沿着 y=x^{2} 曲线从小到大变化。其中切线斜率为 0 的地方恰好是 y=0 (x轴)的位置。二维空间的曲线是这样,三维空间的切线通常是沿着曲面方的x轴和y轴的方向作的,如图8-10所示为 z=x^{2}+y^{2} 的图像,先做一个剖面。剖面本身也会形成一个二维的曲线方程,再让切线沿着这个剖面上的二维曲线方程滑动,找到斜率为0的地方。这也就是 \frac{\partial Q}{\partial a} 和 \frac{\partial Q}{\partial b}
各自的含义了。图8-9 求曲线上斜率为0的地方如果 \frac{\partial Q}{\partial a} =0,且 \frac{\partial Q}{\partial b} =0,解出这两个方程之后就能分别找到 a 的取值能让 Q 产生极值的条件,以及 b 的取值能让 Q 产生极值的条件,即找到了 a 、b 两个维度上类似y=\left[\left(x+\frac{b}{2 a}\right)^{2}+\frac{4 a c-b^{2}}{4 a^{2}}\right]中函数曲线的切线为 0 的情况。分别求导后:\begin{aligned}
&\frac{\partial Q}{\partial a}=2 \sum_{i=1}^{n}\left[x_{i}\left(a x_{i}+b-y_{i}\right)\right]=0 \\
&\frac{\partial Q}{\partial b}=2 \sum_{i=1}^{n}\left(a x_{i}+b-y_{i}\right)=0
\end{aligned}找满足上式的 a 和 b 的取值。Q 是一个误差的平方和,a 和 b 是斜率和截距,现在要能找到一个极值必定是一个使 Q 最小的极值。证明略,读者可以想像用直线在纸上穿点的过程,谨小慎微地穿能找到一个误差最小的点,稍微偏一偏这个误差就很大,而且越偏越大,那么这个大的极值点是不存在的,小的极值点是存在的,也就是要求解的点。图8-10 $z=x^{2}+y^{2}$ 的图像(见彩插)如果实在不知道为什么求偏微分会得到\frac{\partial Q}{\partial a}=2 \sum_{i=1}^{n}\left[x_{i}\left(a x_{i}+b-y_{i}\right)\right]和\frac{\partial Q}{\partial b}=2 \sum_{i=1}^{n}\left(a x_{i}+b-y_{i}\right),那就先囫囵吞枣往下看,只要还记得这个是我们要求的结果,根据上述得到的求导之后得 0 的两个等式可以把公式展开推导出a \sum_{i=1}^{n} x_{i}^{2}+b \sum_{i=1}^{n} x_{i}=\sum_{i=1}^{n} y_{i} x_{i}其实是\frac{\partial Q}{\partial a}=0展开,把 a 和 b 作为系数提出去之后的结果。同理a \sum_{i=1}^{n} x_{i}+b \sum_{i=1}^{n} 1=\sum_{i=1}^{n} y_{i}这是\frac{\partial Q}{\partial b}=0展开,把 a 和 b 作为系数提出去之后的结果。这样得到一个方程组:\begin{aligned}
&a \sum_{i=1}^{n} x_{i}^{2}+b \sum_{i=1}^{n} x_{i}=\sum_{i=1}^{n} y_{i} x_{i} \\
&a \sum_{i=1}^{n} x_{i}+N b=\sum_{i=1}^{n} y_{i}
\end{aligned}把(2)式做如下处理:(2) \cdot \frac{\sum_{i=1}^{n} x_{i}}{N}-(1)得到下面的等式:a\left(\sum_{i=1}^{n} x_{i} \cdot \frac{\sum_{i=1}^{n} x_{i}}{n}-\sum_{i=1}^{n} x_{i}^{2}\right)=\sum_{i=1}^{n} y_{i} \cdot \frac{\sum_{i=1}^{n} x_{i}}{n}-\sum_{i=1}^{n} y_{i} x_{i}把a和b各自的表达式推导出来:a=\frac{\frac{\sum_{i=1}^{n} y_{i} \cdot \sum_{i=1}^{n} x_{i}}{n}-\sum_{i=1}^{n} y_{i} x_{i}}{\frac{\sum_{i=1}^{n} x_{i} \cdot \sum_{i=1}^{n} x_{i}}{n}-\sum_{i=1}^{n} x_{i}^{2}}b=\frac{\sum_{i=1}^{n} y_{i}-a \sum_{i=1}^{n} x_{i}}{n}其中,a 就是斜率,b 是截距。上式中,把所有的观测值 x 和 y 都代入,就可以得出a;再把观测值和已经求出的 a 代入下式,就可以相应得出 b 。在Python中,有一些框架可以直接使用最小二乘法进行线性拟合。例如:import numpy as np
import matplotlib.pyplot as plt
#原始数据
x = [1,2,3,4,5,6,7,8,9]
y = [0.199, 0.389, 0.580, 0.783, 0.980, 1.177, 1.380, 1.575, 1.771]
t1 = t2 = t3 = t4 = 0
n = len(x)
for i in range(n):
t1 += y[i]
#∑y
t2 += x[i]
#∑x
t3 += x[i]*y[i] #∑xy
t4 += x[i]**2
#∑x^2
a = (t1*t2/n - t3) / (t2*t2/n - t4)
b = (t1 - a*t2) / n
x = np.array(x)
y = np.array(y)
#画图
plt.plot(x, y, 'o', label='Original data', markersize=10)
plt.plot(x, a*x + b, 'r', label='Fitted line')
plt.show()
8.4 过拟合过拟合简称“过拟”,是在拟合过程中出现的一种“做过头”的情况。怎么叫做过头呢?我们通过对数据样本的观察和抽象,最后归纳得到一个完整的数据映射模型。但是在归纳的过程中,可能为了迎合所有样本向量点甚至是噪声点而使得模型描述过于复杂。过度拟合的危害有以下几点。(1)描述复杂。所有的过度拟合的模型都有一个共同点,那就是模型的描述非常复杂——参数繁多,计算逻辑多。(2)失去泛化能力。所谓泛化能力就是通过学习(或机器学习)得到的模型对未知数据的预测能力,即应用于其他非训练样本的向量时的分类能力。对于待分类样本向量分类正确度高,表示泛化能力比较好;反之,如果对于待分类样本向量分类正确度低,则表示泛化能力较差。我们通常希望模型的泛化能力是比较好的,因为没有泛化能力的模型对于生产指导基本没有什么意义。造成过拟合的原因比较多,最常见的是以下两种。(1)训练样本太少。对于训练样本过少的情况,通常都会归纳出一个非常不准确的模型。例如,要通过样本统计的方式来进行疾病成因总结,只有一个病例时,这一个病例自身的个案特点很可能会被当成通用性的特点,这样总结出来的模型显然没有泛化能力。而样本多时就可以通过统计分析保留那些共性较多的特点,而共性较少的特点就是我们所说的噪声——就不会被当做分类参数。(2)力求“完美”。对于所有的训练样本向量点都希望用拟合的模型覆盖,但是实际上的训练样本却有很多是带有噪声的。这里说的噪声不是指刺耳的破坏心情的声响,而是在收集到的训练数据中由于各种原因导致的与预期分类不一致的样本向量。如上述打点过程中,小车轮子的摩擦不均匀,纸张粗糙程度不同,导致某些点打出来比理想时间要晚,或比理想时间要早,当偏差比我们预期大很多时就可以认为该点是噪声点了。再如,如果想测量两地之间的平均行车时间,选100辆汽车加装计时设备进行测试,所有车辆从A地出发前往B地。其中97辆车计时设备读数都是20~22分钟,有1辆车由于超速行驶计时设备读数为15分钟,有1辆车由于车辆故障中途抛锚计时设备读数300分钟,有1辆车由于忘记开启计时器计时设备读数0分钟。在这个例子中,基本可以判断A地到B地行车时间为21分钟左右,而后面的3个数据:15分钟、300分钟和0分钟就是典型的噪声数据了,完全可以在建模的过程中舍弃。如果穷尽所有的办法都没办法舍弃这些噪声点而又力求让模型描述覆盖这些点,那将是非常可怕的,归纳出来的模型会产生很大的偏差。在上述残差分析中,尝试着将误差e这个部分做成一个以0为中心的正态分布。如果希望这个正态分布中σ小一些,甚至为0。在这个过程中会出现什么现象?首先,在分析的过程中已经尝试着用最小二乘法确定系数,这种情况已经比胡乱确定任何一个系数要合理得多,因为大部分情况下误差都很小。误差为0的这种极限是什么呢?其实是类似分段函数,以上述打点计时器为例:\begin{array}{cc}
v_{n}=0.078, & n=1 \\
v_{n}=0.100, & n=2 \\
v_{n}=0.118, & n=3 \\
\cdots & \\
v_{n}=0.290, & n=12
\end{array}这种描述的啰嗦程度几乎没有任何回归后的简洁可言,况且,v=gt 并不是一个离散函数,t 是一个在非负实数上连续的自变量,难道有任何办法罗列出所有的值吗?当然不可能,甚至连实验得到的数据内容都是有限的。在多元线性回归的过程中也会有类似的情况,在为了使得误差尽可能小的过程中,会同时使得函数的描述变得过于复杂,以至于大大提高使用成本,那么这种减小误差的行为其实是得不偿失的。所有这种使得函数的描述变得过于复杂,或者参数过于繁多,或者由于训练样本的问题导致函数失去泛化特性的拟合过程都叫做过度拟合(Overfitting)。8.5 欠拟合与过度拟合相反,还有一种现象叫做欠拟合,简称欠拟。欠拟顾名思义,就是由于操作不当——也可以说建模不当产生的误差e分布太散或者太大的情况。这种情况下,通常体现出来的都是在线性回归中的因素考虑不足的情况,常见的原因有以下两种。(1)参数过少。对于训练样本向量的维度提取太少会导致模型描述的不准确。例如,要根据银行储户的信息来判断其信誉好或不好,通常需要综合考虑用户的年龄、流水总和、账户余额、借贷频次、借贷额度、归还准时程度等信息特征。这些因素考虑得越充分,通常对于用户的信誉好或不好,给予的信用额度多少为宜就会有比较可靠的预测程度。而如果参数太少,如只有账户余额一项,那么就不得不用账户余额一个参数和信誉好坏去建立一个模型映射关系。这个模型是很不科学的,通过一个余额的数字就能断言一个人信誉几何太过武断。(2)拟合不当。拟合不当的原因比较复杂,通常是拟合方法不正确造成的。例如,某个训练样本向量x与结果值y之间的关系如下:(1,1)(1.41,2)(1.7,3)(2.1,4)形成这4组向量以后,用 y=x^{2} 在第一象限的曲线去拟合误差更小。而如果用图8-11所示的直线 y=3.732x-2.932 做拟合,显然都没有y=x2的误差小。图8-11 用直线y=3.732x-2.932拟合凡是在欠拟合时,都要重新考虑建模是不是有考虑欠缺的地方。因为误差太大以至于拟合函数没有泛化能力而失去指导意义,这与没有做拟合差不多。8.6 曲线拟合转化为线性拟合非线性回归的情况太过复杂,在生产实践中也尽量避免使用这种模型。好在分类算法有很多,而且更多的是为了处理半结构化数据,所以非线性回归相关的内容只做一般性了解即可。非线性回归一般可以分为一元非线性回归和多元非线性回归。一元非线性回归是指两个变量——一个自变量,一个因变量之间呈现非线性关系,如双曲线、二次曲线、三(多)次曲线、幂曲线、指数曲线、对数曲线等。在解决这些问题时通常建立的是非线性回归方程或者方程组。多元非线性回归分析是指两个或两个以上自变量和因变量之间呈现的非线性关系建立非线性回归模型。对多元非线性回归模型求解的传统做法,仍然是想办法把它转化成标准的线性形式的多元回归模型来处理。有些非线性回归模型,经过适当的数学变换,便能得到它的线性化的表达形式,但对另外一些非线性回归模型,仅仅做变量变换根本无济于事。属于前一种情况的非线性回归模型一般称为内蕴的线性回归,而后者则称之为内蕴的非线性回归。线性拟合里最简单的就是上述y=ax+b这种形式。除此之外,可以将等式两边转化为几个一次式加和的情况,不论是一元的还是多元的,都仍然是线性回归研究的范畴。再如:20世纪60年代的世界人口状况如表8-2所示。表8-2 20世纪60年代世界人口状况根据马尔萨斯人口模型:S=\alpha \cdot \mathrm{e}^{\beta t}其中 s 是人口,t 是年份,e 是自然常数(约取2.71828),试着推导一下到2030年时世界人口的数量。这个问题是一个比较典型的多元线性回归的问题模型。求解如下。对等式两边同时取 ln(以 e 为底的 log),得到\ln s=\beta t+\ln \alpha在这里实际上用的还是线性回归模型,相当于y=a x+b且\ln s=y\beta=a\ln \alpha=b这种使用方式在Python中同样可以套用线性回归的方法,代码如下:import numpy as np
from scipy.optimize import curve_fit
import matplotlib.pyplot as plt
#原始数据
T = [1960, 1961, 1962, 1963, 1964, 1965, 1966, 1967, 1968]
S = [29.72, 30.61, 31.51, 32.13, 32.34, 32.85, 33.56, 34.20, 34.83]
xdata = np.array(T)
ydata = np.log(np.array(S)
def func(x, a, b):
return a + b*x
#使用非线性最小二乘法拟合函数
popt, pcov = curve_fit(func, xdata, ydata)
#画图
plt.plot(xdata, ydata, 'ko', label="Original Noised Data")
plt.plot(xdata, func(xdata, *popt), 'r', label="Fitted Curve")
plt.show()
如图8-12所示,横轴写着+1.96e3,这是用科学记数法来表示的,意思为1.96×103,也就是1960,横轴上的点就是1960~1968。纵轴是 \ln s 的值,斜率是β的值,截距是 \ln \alpha 的值,计算完成后通过代换可以计算出 \beta 和 \alpha 的值。图8-12 线性回归函数图形在这个例子中,最后可以得到 \beta=0.01859, \alpha=4.48401395866716 \times 10^{-15}代入公式 s=\alpha \cdot e^{\beta t},求得 s 的值,单位是亿。在预测人口数量时,直接把年份代入即可,如2000年时,代入公式得到 s 约为62.9亿。关于马尔萨斯人口模型公式 s=\alpha \cdot e^{\beta t} 有一个需要注意的地方,即预测近期的人口数据基本准确,如2000年的人口,使用这个模型预测出来是62.9亿,真实的统计数据为61.02亿,误差不到3.1%,还是一个相对比较精确的模型。但是代入更大的数字就会出现问题,如代入4000这个数字,算出来大约88263万亿,这个数字是不可信的,因为公元4000年的时候世界人口数量增大至现在的1200多万倍,按照地球陆地面积1.49亿平方千米计算,平均每平方米上有592个人而且不管是高山峡谷沼泽森林统统都算在内。这种现象可不是这一个例子里所特有的,所有的由统计而来的回归方程在自变量很大或者很小时都容易发生失真。所以回归这种模型只能用来预测和自变量统计的区间比较近的自变量对应的函数值。8.7 小结从机器学习的角度来说,回归算法应该算作“分类”算法。它更像是人们先给了计算机一些样本,然后让计算机根据样本计算出一种公式或者模型,而在公式或者模型成立后,人们再给这个模型新的样本,它就可以把这个样本猜测或者说推断为某一分类。不同的是,在回归中研究的都是具体的数值(实数),而分类算法则不一定,它的样本除了可以是数值外,可能很多是一些枚举值或者文本。读者只需要从这个角度来做感性上的区分即可。在使用回归的过程中,要注意尽量避免出现过拟和欠拟,让函数描述在简洁和精确之间找一个平衡,这才是众多从统计而来的回归过程最后落地所要考虑的事情。过拟和欠拟不仅出现在回归方法中,在其他基于样本向量的统计归纳的模型训练中都有这样的问题,请读者一定要注意。本文使用 Zhihu On VSCode 创作并发布

我要回帖

更多关于 线性回归的前提条件 的文章

 

随机推荐