一.线性回归
线性回归就是将输入项分别乘以一些常量,在将结果加起来得到输出。 假定输入数据存放在矩阵 x 中,而回归系数存放在向量 w 中。 那么预测结果可以通过Y=X的转置*W得出。所以我们求解线性回归模型的核心就在于求解w,如何求呢?首先,我们一定是希望预测出来的值和实际值之间的误差越小越好,所以我们评判w好坏,就可以采用实际值与真实值之差表示,但是这个差有正有负,为了避免正负相互抵消的情况,我们采用平方误差(也就是最小二乘法)
平方误差,我们也可以叫他损失函数。我们现在就是要以w为变量求解损失函数的最小值。
我们可以对w进行求导,令其为0,可得到我们所要求解w所需的计算公式。
局部加权线性回归
线性回归的一个问题是有可能出现欠拟合现象,因为它求的是具有小均方误差的无偏估 计。显而易见,如果模型欠拟合将不能取得好的预测效果。所以有些方法允许在估计中引入一 些偏差,从而降低预测的均方误差。
其中的一个方法是局部加权线性回归。在该算法中,我们给待预测点附近的每个点赋予一定的权重;在这个子集上基于 小均方差来进行普通的回归。
局部加权线性回归的基本思想:设计代价函数时,待预测点附近的点拥有更高的权重,权重随着距离的增大而缩减——这也就是名字中“局部”和“加权”的由来。
权重如何求取:
区别在于此时的代价函数中多了一个权重函数W,这个W要保证,越靠近待测点附近权值越大,越远离待测点权值越小。 这个函数W一般取用:x是待测点,k控制了权值变化的速率,k越大,图像越瘦,离x越远权值下降越快
局部加权线性回归存在的问题
增加了计算量,对每个数据点做预测的时候都必须使用整个数据集合。有点类似与kmean算法
缩减系数来“理解”数据
如果数据的特征比样本点还多,会导致在计算(XTX)-1的时候会出错。也就是说输入数据的矩阵x不是满秩矩阵。非满秩矩阵在求逆的时候会出错。为了解决这个问题所以引入了岭回归。
岭回归
岭回归就是在矩阵X.TX上加一个λI从而使得矩阵非奇异,进而能对X.TX + λI求逆。其中矩阵I是一个m×m的单位矩阵,对角线上元素全为1,其他元素全为0。而λ是一个用户定义的 数值。在这种情况下,回归系数的计算公式将变成:
通过引入λ来限制了所有w之和,通过引入该惩罚项,能够减少不重要的参数,这 个技术在统计学中也叫做缩减(shrinkage)。
岭回归中的岭是什么?单位举证I的对角线上面都是1,其他元素都是0。看起来就像是1组成的岭。
岭回归在鲍鱼数据集上的运行效果
λ非常小时,系数与普通回归一样。而λ非常大时, 所有回归系数缩减为0。可以在中间某处找到使得预测的结果好的λ值
前向逐步回归
前向逐步回归算法可以得到与lasso差不多的效果,但更加简单。它属于一种贪心算法,即每 一步都尽可能减少误差。一开始,所有的权重都设为1,然后每一步所做的决策是对某个权重增 加或减少一个很小的值。
权衡偏差与方差
下面曲线是训练误差,上面的是测试误差,随着核减少,模型复杂度增大,虽然在训练误差上不断减少,但是 测试误差上会随着模型复杂度增加先减少再增加。 可以将一些系数缩减成很小的值或直接缩减为 0 ,这是一个增大模型偏差的例子。通过把一些特征的回归系数缩减到 0 ,同时也就减小了模型的复杂度。 对照上图,左侧是参数缩减过于严厉的结果,而右侧是无缩减的效果。
#!/usr/bin/python
# coding:utf8
'''
Created on Jan 8, 2011
Update on 2017-05-18
Author: Peter Harrington/小瑶
GitHub: https://github.com/apachecn/AiLearning
'''
from __future__ import print_function
from numpy import *
import matplotlib.pylab as plt
def loadDataSet(fileName):
""" 加载数据
解析以tab键分隔的文件中的浮点数
Returns:
dataMat : feature 对应的数据集
labelMat : feature 对应的分类标签,即类别标签
"""
# 获取样本特征的总数,不算最后的目标变量
numFeat = len(open(fileName).readline().split('\t')) - 1
dataMat = []
labelMat = []
fr = open(fileName)
for line in fr.readlines():
# 读取每一行
lineArr = []
# 删除一行中以tab分隔的数据前后的空白符号
curLine = line.strip().split('\t')
# i 从0到2,不包括2
for i in range(numFeat):
# 将数据添加到lineArr List中,每一行数据测试数据组成一个行向量
lineArr.append(float(curLine[i]))
# 将测试数据的输入数据部分存储到dataMat 的List中
dataMat.append(lineArr)
# 将每一行的最后一个数据,即类别,或者叫目标变量存储到labelMat List中
labelMat.append(float(curLine[-1]))
return dataMat, labelMat
def standRegres(xArr, yArr):
'''
Description:
线性回归
Args:
xArr :输入的样本数据,包含每个样本数据的 feature
yArr :对应于输入数据的类别标签,也就是每个样本对应的目标变量
Returns:
ws:回归系数
'''
# mat()函数将xArr,yArr转换为矩阵 mat().T 代表的是对矩阵进行转置操作
xMat = mat(xArr)
yMat = mat(yArr).T
# 矩阵乘法的条件是左矩阵的列数等于右矩阵的行数
xTx = xMat.T * xMat
# 因为要用到xTx的逆矩阵,所以事先需要确定计算得到的xTx是否可逆,条件是矩阵的行列式不为0
# linalg.det() 函数是用来求得矩阵的行列式的,如果矩阵的行列式为0,则这个矩阵是不可逆的,就无法进行接下来的运算
if linalg.det(xTx) == 0.0:
print("This matrix is singular, cannot do inverse")
return
# 最小二乘法
# http://cwiki.apachecn.org/pages/viewpage.action?pageId=5505133
# 书中的公式,求得w的最优解
ws = xTx.I * (xMat.T * yMat)
return ws
# 局部加权线性回归
def lwlr(testPoint, xArr, yArr, k=1.0):
'''
Description:
局部加权线性回归,在待预测点附近的每个点赋予一定的权重,在子集上基于最小均方差来进行普通的回归。
Args:
testPoint:样本点
xArr:样本的特征数据,即 feature
yArr:每个样本对应的类别标签,即目标变量
k:关于赋予权重矩阵的核的一个参数,与权重的衰减速率有关
Returns:
testPoint * ws:数据点与具有权重的系数相乘得到的预测点
Notes:
这其中会用到计算权重的公式,w = e^((x^((i))-x) / -2k^2)
理解:x为某个预测点,x^((i))为样本点,样本点距离预测点越近,贡献的误差越大(权值越大),越远则贡献的误差越小(权值越小)。
关于预测点的选取,在我的代码中取的是样本点。其中k是带宽参数,控制w(钟形函数)的宽窄程度,类似于高斯函数的标准差。
算法思路:假设预测点取样本点中的第i个样本点(共m个样本点),遍历1到m个样本点(含第i个),算出每一个样本点与预测点的距离,
也就可以计算出每个样本贡献误差的权值,可以看出w是一个有m个元素的向量(写成对角阵形式)。
'''
# mat() 函数是将array转换为矩阵的函数, mat().T 是转换为矩阵之后,再进行转置操作
xMat = mat(xArr)
yMat = mat(yArr).T
# 获得xMat矩阵的行数
m = shape(xMat)[0]
# eye()返回一个对角线元素为1,其他元素为0的二维数组,创建权重矩阵weights,该矩阵为每个样本点初始化了一个权重
weights = mat(eye((m)))
for j in range(m):
# testPoint 的形式是 一个行向量的形式
# 计算 testPoint 与输入样本点之间的距离,然后下面计算出每个样本贡献误差的权值
diffMat = testPoint - xMat[j, :]
# k控制衰减的速度
weights[j, j] = exp(diffMat * diffMat.T / (-2.0 * k**2