Chapter8 回归
回归:简单说就是“由果索因”的过程,是一种归纳的思想
当看到大量的事实所呈现的样态,推断出原因是如何的;当看到大量的数字对是某种样态,推断出它们之间蕴含的关系是如何的。
线性回归是利用数理统计学中的回归分析来确定两种或两种以上变量间相互依赖的定量关系的一种统计分析方法。其表达形式如下:
y=ax+b+e,e为误差服从均值为0的正态分布
从大量的函数结果和自变量反推回函数表达式的过程就是回归
把平面上一系列的点用一条光滑的曲线连接起来的过程就叫做拟合
"""
用线性回归的方法实现高中利用打点计时器
求重力加速度的方法
"""
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
print(A)
# 调用最小二乘法函数
a, b = np.linalg.lstsq(A, y, rcond=None)[0]
print(a, b)
# 转换成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.legend()
plt.show()
系数究竟取多少才能让e最小,这个过程就是残差分析
最小二乘法是一种非常经典的用来进行线性回归中系数猜测的方法
"""
使用最小二乘法进行线性拟合
"""
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]
t2 += x[i]
t3 += x[i]*y[i]
t4 += x[i]**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.legend()
plt.show()
过拟合:简称“过拟”,是在拟合过程中出现的一种“做过头”的情况
通过对数据样本的观察和抽象,最后归纳得到一个完整的数据映射模型。但是在归纳的过程中,可能为了迎合所有样本向量点甚至是噪声点而使得模型描述过于复杂。
过度拟合的危害:
- 描述复杂。所有过拟合的模型都有一个共同点,那就是模型的描述非常复杂,参数繁多,计算逻辑多。
- 失去泛化能力。泛化能力是通过学习(或机器学习)得到的模型对未知数据的预测能力,即应用于其他非训练样本的向量时的分类能力。
造成过拟合的常见原因:
- 训练样本太少。对于训练样本过少的情况,通常都会归纳出一个非常不准确的模型。样本多时就可以通过统计分析保留那些共性较多的特点,而共性较少的特点就是我们所说的噪声就不会被当作分类参数。
- 力求“完美”。对于所有的训练样本向量点都希望用拟合的模型覆盖,但是实际上的训练样本却有很多是带有噪声的。如果穷尽所有的办法都无法舍弃这些噪声点而又力求让模型描述覆盖这些点,那将是非常可怕的,归纳出来的模型会产生很大的偏差。
所有这种使得函数的描述过于复杂,或者参数过于繁多,或者由于训练样本的问题导致函数失去泛化特性的拟合过程都叫做过度拟合。
欠拟合:简称“欠拟”,由于操作不当,也可以说建模不当产生的误差e分布太散或者太大的情况。通常体现出来的都是在线性回归中的因素考虑不足的情况。
欠拟合的常见原因:
- 参数过少。对于训练样本向量的维度提取太少会导致模型描述的不准确。
- 拟合不当。拟合方法不正确。
凡是在欠拟合时,都要重新考虑建模是不是有考虑欠缺的地方。
非线性回归一般可以分为一元非线性回归和多元非线性回归。
一元非线性回归是指两个变量,一个自变量一个因变量之间呈现的非线性关系,解决这些问题时通常建立的是非线性回归方程或方程组。
多元非线性回归分析是指两个或者两个以上自变量和因变量之间呈现的非线性关系建立非线性回归模型。求解多元非线性回归模型的传统做法是,想办法把它转化成标准的线性形式的多元回归模型来处理。有些非线性回归模型,经过适当的数学变化,便能得到它的线性化的表达形式,该类非线性回归模型一般称为内蕴的线性回归;但对另外一些非线性回归模型,仅仅做变量变换根本无济于事,此类非线性回归模型称为内蕴的非线性回归。
"""
曲线拟合转化为线性拟合
"""
import numpy as np
from scipy.optimize import curve_fit
import matplotlib.pyplot as plt
import math
# 原始数据
T = [1960, 1961, 1962, 1963, 1964, 1965, 1966, 1967, 1968]
S = [29.72, 30.61, 31.51, 32.13, 32.24, 32.85, 33.56, 34.20, 34.83]
xdata = np.array(T)
ydata = np.log(np.array(S))
print(xdata)
print(ydata)
def func(x, a, b):
return a+b*x
# 使用非线性最小二乘法拟合函数
popt, pcov = curve_fit(func, xdata, ydata)
print(popt)
# 画图
plt.plot(xdata, ydata, 'ko', label="Original Noised Data")
plt.plot(xdata, func(xdata, *popt), 'r', label="Fitted Curve")
plt.legend()
plt.show()
print(math.e ** func(2000, *popt))
"""
对一组数据进行不同形式的曲线拟合对比
"""
import numpy as np
import matplotlib.pyplot as plt
from scipy import optimize
# 直线方程函数
def f_1(x, A, B):
return A*x +B
# 二次曲线方程
def f_2(x, A, B, C):
return A*x*x +B*x +C
# 三次曲线方程
def f_3(x, A, B, C, D):
return A*x*x*x +B*x*x +C*x +D
def plot_test():
plt.figure()
# 拟合点
x0 = [1, 2, 3, 4, 5]
y0 = [1, 3, 8, 18, 36]
# 绘制散点
plt.scatter(x0[:], y0[:], 25, "red")
# 直线拟合与绘制
A1, B1 = optimize.curve_fit(f_1, x0, y0)[0]
x1 = np.arange(0, 6, 0.01)
y1 = A1*x1 +B1
plt.plot(x1, y1, "blue", label="Linear fitting")
# 二次曲线拟合与绘制
A2, B2, C2 = optimize.curve_fit(f_2, x0, y0)[0]
x2 = np.arange(0, 6, 0.01)
y2 = A2*x2*x2 + B2*x2 +C2
plt.plot(x2, y2, "green", label="Quadratic curve fitting")
# 三次曲线拟合与绘制
A3, B3, C3, D3 = optimize.curve_fit(f_3, x0, y0)[0]
x3 = np.arange(0, 6, 0.01)
y3 = A3*x3*x3*x3 + B3*x3*x3 + C3*x3 + D3
plt.plot(x3, y3, "purple", label="Cubic curve fitting")
plt.title("curve_fit")
plt.xlabel('x')
plt.ylabel('y')
plt.legend()
plt.show()
return 0
if __name__ == "__main__":
plot_test()
从机器学习的角度来说,回归算法应该算作“分类”算法。
不同的是,在回归中研究的都是具体的数值(实数),而分类算法则不一定,它的样本除了可以是数值外,可能很多是一些枚举值或者文本。
在使用回归的过程中,要注意尽量避免出现过拟和欠拟,让函数描述在简洁和精确之间找一个平衡,这才是众多从统计而来的回归过程最后落地所要考虑的事情。
过拟和欠拟不仅出现在回归方法中,在其他基于样本向量的统计归纳的模型训练中都有这样的问题。