修改8.Regression文档和代码
@@ -21,9 +21,11 @@ HorsePower = 0.0015 * annualSalary - 0.99 * hoursListeningToPublicRadio
|
||||
|
||||
## 回归 原理
|
||||
|
||||
### 回归 须知概念
|
||||
### 1、线性回归
|
||||
|
||||
#### 1、矩阵求逆
|
||||
#### 1.1、线性回归 须知概念
|
||||
|
||||
##### 1.1.1、矩阵求逆
|
||||
|
||||
因为我们在计算回归方程的回归系数时,用到的计算公式如下:
|
||||
|
||||
@@ -34,11 +36,11 @@ HorsePower = 0.0015 * annualSalary - 0.99 * hoursListeningToPublicRadio
|
||||
|
||||
判断矩阵的行列式是否为 0,若为 0 ,矩阵就不存在逆矩阵,不为 0 的话,矩阵才存在逆矩阵。
|
||||
|
||||
#### 2、最小二乘法
|
||||
##### 1.1.2、最小二乘法
|
||||
|
||||
最小二乘法(又称最小平方法)是一种数学优化技术。它通过最小化误差的平方和寻找数据的最佳函数匹配。
|
||||
|
||||
### 回归 工作原理
|
||||
#### 1.2、线性回归 工作原理
|
||||
|
||||
```
|
||||
读入数据,将数据特征想、特征标签y存储在矩阵x、y中
|
||||
@@ -46,7 +48,7 @@ HorsePower = 0.0015 * annualSalary - 0.99 * hoursListeningToPublicRadio
|
||||
使用最小二乘法求得 回归系数 w 的最佳估计
|
||||
```
|
||||
|
||||
### 回归 开发流程
|
||||
#### 1.3、线性回归 开发流程
|
||||
|
||||
```
|
||||
收集数据: 采用任意方法收集数据
|
||||
@@ -57,7 +59,7 @@ HorsePower = 0.0015 * annualSalary - 0.99 * hoursListeningToPublicRadio
|
||||
使用算法: 使用回归,可以在给定输入的时候预测出一个数值,这是对分类方法的提升,因为这样可以预测连续型数据而不仅仅是离散的类别标签
|
||||
```
|
||||
|
||||
### 回归 算法特点
|
||||
#### 1.4、线性回归 算法特点
|
||||
|
||||
```
|
||||
优点:结果易于理解,计算上不复杂。
|
||||
@@ -65,27 +67,484 @@ HorsePower = 0.0015 * annualSalary - 0.99 * hoursListeningToPublicRadio
|
||||
适用于数据类型:数值型和标称型数据。
|
||||
```
|
||||
|
||||
#### 1.5、线性回归 项目案例
|
||||
|
||||
> 线性回归的效果图
|
||||
##### 1.5.1、线性回归 项目概述
|
||||
|
||||

|
||||
根据下图中的点,找出该数据的最佳拟合直线。
|
||||
|
||||
## 局部加权线性回归
|
||||

|
||||
|
||||
> 局部加权线性回归简介
|
||||
数据格式为:
|
||||
|
||||
```
|
||||
线性回归的一个问题是有可能出现欠拟合现象,因为它求的是具有最小均方误差的无偏估计。显而易见,如果模型欠拟合将不能取得最好的预测效果。
|
||||
所以有些方法允许在估计中引入一些偏差,从而降低预测的均方差。
|
||||
其中的一个方法是局部加权线性回归(Locally Weighted Linear Regression, LWLR)。在该算法中,我们给带预测点附近的每个点赋予一定的权重,
|
||||
在这个子集上基于最小均方差来进行普通的回归。与kNN一样,这种算法每次预测均需要实现选取出对应的数据子集。该算法解出回归系数w的形式如下:
|
||||
w = (X^T W X)^(-1)X^T Wy
|
||||
1.000000 0.067732 3.176513
|
||||
1.000000 0.427810 3.816464
|
||||
1.000000 0.995731 4.550095
|
||||
1.000000 0.738336 4.256571
|
||||
```
|
||||
|
||||
##### 1.5.2、线性回归 编写代码
|
||||
|
||||
```python
|
||||
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://www.apache.wiki/pages/viewpage.action?pageId=5505133
|
||||
# 书中的公式,求得w的最优解
|
||||
ws = xTx.I * (xMat.T*yMat)
|
||||
return ws
|
||||
|
||||
|
||||
def regression1():
|
||||
xArr, yArr = loadDataSet("input/8.Regression/data.txt")
|
||||
xMat = mat(xArr)
|
||||
yMat = mat(yArr)
|
||||
ws = standRegres(xArr, yArr)
|
||||
fig = plt.figure()
|
||||
ax = fig.add_subplot(111) #add_subplot(349)函数的参数的意思是,将画布分成3行4列图像画在从左到右从上到下第9块
|
||||
ax.scatter(xMat[:, 1].flatten(), yMat.T[:, 0].flatten().A[0]) #scatter 的x是xMat中的第二列,y是yMat的第一列
|
||||
xCopy = xMat.copy()
|
||||
xCopy.sort(0)
|
||||
yHat = xCopy * ws
|
||||
ax.plot(xCopy[:, 1], yHat)
|
||||
plt.show()
|
||||
```
|
||||
|
||||
##### 1.5.3、线性回归 拟合效果
|
||||
|
||||

|
||||
|
||||
|
||||
### 2、局部加权线性回归
|
||||
|
||||
线性回归的一个问题是有可能出现欠拟合现象,因为它求的是具有最小均方差的无偏估计。显而易见,如果模型欠拟合将不能取得最好的预测效果。所以有些方法允许在估计中引入一些偏差,从而降低预测的均方误差。
|
||||
|
||||
一个方法是局部加权线性回归(Locally Weighted Linear Regression,LWLR)。在这个算法中,我们给预测点附近的每个点赋予一定的权重,然后与 线性回归 类似,在这个子集上基于最小均方误差来进行普通的回归。与 kNN 一样,这种算法每次预测均需要事先选取出对应的数据子集。该算法解出回归系数 w 的形式如下:
|
||||
|
||||

|
||||
|
||||
其中 w 是一个矩阵,用来给每个数据点赋予权重。
|
||||
|
||||
LWLR 使用 “核”(与支持向量机中的核类似)来对附近的点赋予更高的权重。核的类型可以自由选择,最常用的核就是高斯核,高斯核对应的权重如下:
|
||||
|
||||

|
||||
|
||||
这样就构建了一个只含对角元素的权重矩阵 **w**,并且点 x 与 x(i) 越近,w(i, i) 将会越大。上述公式中包含一个需要用户指定的参数 k,它决定了对附近的点赋予多大的权重,这也是使用 LWLR 时唯一需要考虑的参数,下面的图给出了参数 k 与权重的关系。
|
||||
|
||||

|
||||
|
||||
上面的图是 每个点的权重图(假定我们正预测的点是 x = 0.5),最上面的图是原始数据集,第二个图显示了当 k = 0.5 时,大部分的数据都用于训练回归模型;而最下面的图显示当 k=0.01 时,仅有很少的局部点被用于训练回归模型。
|
||||
|
||||
#### 2.1、局部加权线性回归 工作原理
|
||||
|
||||
```
|
||||
读入数据,将数据特征想、特征标签y存储在矩阵x、y中
|
||||
利用高斯核构造一个权重矩阵 W,对预测点附近的点施加权重
|
||||
验证 X^TWX 矩阵是否可逆
|
||||
使用最小二乘法求得 回归系数 w 的最佳估计
|
||||
```
|
||||
|
||||
> 局部加权线性回归效果图
|
||||
#### 2.2、局部加权线性回归 项目案例
|
||||
|
||||
##### 2.2.1、局部加权线性回归 项目概述
|
||||
|
||||
我们仍然使用上面 线性回归 的数据集,对这些点进行一个 局部加权线性回归 的拟合。
|
||||
|
||||

|
||||
|
||||
数据格式为:
|
||||
|
||||
```
|
||||
1.000000 0.067732 3.176513
|
||||
1.000000 0.427810 3.816464
|
||||
1.000000 0.995731 4.550095
|
||||
1.000000 0.738336 4.256571
|
||||
```
|
||||
|
||||
##### 2.2.2、局部加权线性回归 编写代码
|
||||
|
||||
```python
|
||||
# 局部加权线性回归
|
||||
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))
|
||||
# 根据矩阵乘法计算 xTx ,其中的 weights 矩阵是样本点对应的权重矩阵
|
||||
xTx = xMat.T * (weights * xMat)
|
||||
if linalg.det(xTx) == 0.0:
|
||||
print ("This matrix is singular, cannot do inverse")
|
||||
return
|
||||
# 计算出回归系数的一个估计
|
||||
ws = xTx.I * (xMat.T * (weights * yMat))
|
||||
return testPoint * ws
|
||||
|
||||
def lwlrTest(testArr,xArr,yArr,k=1.0):
|
||||
'''
|
||||
Description:
|
||||
测试局部加权线性回归,对数据集中每个点调用 lwlr() 函数
|
||||
Args:
|
||||
testArr:测试所用的所有样本点
|
||||
xArr:样本的特征数据,即 feature
|
||||
yArr:每个样本对应的类别标签,即目标变量
|
||||
k:控制核函数的衰减速率
|
||||
Returns:
|
||||
yHat:预测点的估计值
|
||||
'''
|
||||
# 得到样本点的总数
|
||||
m = shape(testArr)[0]
|
||||
# 构建一个全部都是 0 的 1 * m 的矩阵
|
||||
yHat = zeros(m)
|
||||
# 循环所有的数据点,并将lwlr运用于所有的数据点
|
||||
for i in range(m):
|
||||
yHat[i] = lwlr(testArr[i],xArr,yArr,k)
|
||||
# 返回估计值
|
||||
return yHat
|
||||
|
||||
def lwlrTestPlot(xArr,yArr,k=1.0):
|
||||
'''
|
||||
Description:
|
||||
首先将 X 排序,其余的都与lwlrTest相同,这样更容易绘图
|
||||
Args:
|
||||
xArr:样本的特征数据,即 feature
|
||||
yArr:每个样本对应的类别标签,即目标变量,实际值
|
||||
k:控制核函数的衰减速率的有关参数,这里设定的是常量值 1
|
||||
Return:
|
||||
yHat:样本点的估计值
|
||||
xCopy:xArr的复制
|
||||
'''
|
||||
# 生成一个与目标变量数目相同的 0 向量
|
||||
yHat = zeros(shape(yArr))
|
||||
# 将 xArr 转换为 矩阵形式
|
||||
xCopy = mat(xArr)
|
||||
# 排序
|
||||
xCopy.sort(0)
|
||||
# 开始循环,为每个样本点进行局部加权线性回归,得到最终的目标变量估计值
|
||||
for i in range(shape(xArr)[0]):
|
||||
yHat[i] = lwlr(xCopy[i],xArr,yArr,k)
|
||||
return yHat,xCopy
|
||||
|
||||
|
||||
#test for LWLR
|
||||
def regression2():
|
||||
xArr, yArr = loadDataSet("input/8.Regression/data.txt")
|
||||
yHat = lwlrTest(xArr, xArr, yArr, 0.003)
|
||||
xMat = mat(xArr)
|
||||
srtInd = xMat[:,1].argsort(0) #argsort()函数是将x中的元素从小到大排列,提取其对应的index(索引),然后输出
|
||||
xSort=xMat[srtInd][:,0,:]
|
||||
fig = plt.figure()
|
||||
ax = fig.add_subplot(111)
|
||||
ax.plot(xSort[:,1], yHat[srtInd])
|
||||
ax.scatter(xMat[:,1].flatten().A[0], mat(yArr).T.flatten().A[0] , s=2, c='red')
|
||||
plt.show()
|
||||
```
|
||||
|
||||
##### 2.2.3、局部加权线性回归 拟合效果
|
||||
|
||||

|
||||
|
||||
上图使用了 3 种不同平滑值绘出的局部加权线性回归的结果。上图中的平滑系数 k =1.0,中图 k = 0.01,下图 k = 0.003 。可以看到,k = 1.0 时的模型效果与最小二乘法差不多,k=0.01时该模型可以挖出数据的潜在规律,而 k=0.003时则考虑了太多的噪声,进而导致了过拟合现象。
|
||||
|
||||
#### 2.3、局部加权线性回归 注意事项
|
||||
|
||||
局部加权线性回归也存在一个问题,即增加了计算量,因为它对每个点做预测时都必须使用整个数据集。
|
||||
|
||||
|
||||
### 3、线性回归 & 局部加权线性回归 项目案例
|
||||
|
||||
到此为止,我们已经介绍了找出最佳拟合直线的两种方法,下面我们用这些技术来预测鲍鱼的年龄。
|
||||
|
||||
#### 3.1、项目概述
|
||||
|
||||
我们有一份来自 UCI 的数据集合的数据,记录了鲍鱼(一种介壳类水生动物)的年龄。鲍鱼年龄可以从鲍鱼壳的层数推算得到。
|
||||
|
||||
#### 3.2、开发流程
|
||||
|
||||
```
|
||||
收集数据: 采用任意方法收集数据
|
||||
准备数据: 回归需要数值型数据,标称型数据将被转换成二值型数据
|
||||
分析数据: 绘出数据的可视化二维图将有助于对数据做出理解和分析,在采用缩减法求得新回归系数之后,可以将新拟合线绘在图上作为对比
|
||||
训练算法: 找到回归系数
|
||||
测试算法: 使用 rssError()函数 计算预测误差的大小,来分析模型的效果
|
||||
使用算法: 使用回归,可以在给定输入的时候预测出一个数值,这是对分类方法的提升,因为这样可以预测连续型数据而不仅仅是离散的类别标签
|
||||
```
|
||||
|
||||
> 收集数据: 采用任意方法收集数据
|
||||
|
||||
> 准备数据: 回归需要数值型数据,标称型数据将被转换成二值型数据
|
||||
|
||||
数据存储格式:
|
||||
|
||||
```
|
||||
1 0.455 0.365 0.095 0.514 0.2245 0.101 0.15 15
|
||||
1 0.35 0.265 0.09 0.2255 0.0995 0.0485 0.07 7
|
||||
-1 0.53 0.42 0.135 0.677 0.2565 0.1415 0.21 9
|
||||
1 0.44 0.365 0.125 0.516 0.2155 0.114 0.155 10
|
||||
0 0.33 0.255 0.08 0.205 0.0895 0.0395 0.055 7
|
||||
```
|
||||
|
||||
> 分析数据: 绘出数据的可视化二维图将有助于对数据做出理解和分析,在采用缩减法求得新回归系数之后,可以将新拟合线绘在图上作为对比
|
||||
|
||||
> 训练算法: 找到回归系数
|
||||
|
||||
使用上面我们讲到的 局部加权线性回归 训练算法,求出回归系数
|
||||
|
||||
> 测试算法: 使用 rssError()函数 计算预测误差的大小,来分析模型的效果
|
||||
|
||||
```python
|
||||
# test for abloneDataSet
|
||||
def abaloneTest():
|
||||
'''
|
||||
Desc:
|
||||
预测鲍鱼的年龄
|
||||
Args:
|
||||
None
|
||||
Returns:
|
||||
None
|
||||
'''
|
||||
# 加载数据
|
||||
abX, abY = loadDataSet("input/8.Regression/abalone.txt")
|
||||
# 使用不同的核进行预测
|
||||
oldyHat01 = lwlrTest(abX[0:99], abX[0:99], abY[0:99], 0.1)
|
||||
oldyHat1 = lwlrTest(abX[0:99], abX[0:99], abY[0:99], 1)
|
||||
oldyHat10 = lwlrTest(abX[0:99], abX[0:99], abY[0:99], 10)
|
||||
# 打印出不同的核预测值与训练数据集上的真实值之间的误差大小
|
||||
print "old yHat01 error Size is :" , rssError(abY[0:99], oldyHat01.T)
|
||||
print "old yHat1 error Size is :" , rssError(abY[0:99], oldyHat1.T)
|
||||
print "old yHat10 error Size is :" , rssError(abY[0:99], oldyHat10.T)
|
||||
|
||||
# 打印出 不同的核预测值 与 新数据集(测试数据集)上的真实值之间的误差大小
|
||||
newyHat01 = lwlrTest(abX[100:199], abX[0:99], abY[0:99], 0.1)
|
||||
print "new yHat01 error Size is :" , rssError(abY[0:99], yHat01.T)
|
||||
newyHat1 = lwlrTest(abX[100:199], abX[0:99], abY[0:99], 1)
|
||||
print "new yHat1 error Size is :" , rssError(abY[0:99], yHat1.T)
|
||||
newyHat10 = lwlrTest(abX[100:199], abX[0:99], abY[0:99], 10)
|
||||
print "new yHat10 error Size is :" , rssError(abY[0:99], yHat10.T)
|
||||
|
||||
# 使用简单的 线性回归 进行预测,与上面的计算进行比较
|
||||
standWs = standRegres(abX[0:99], abY[0:99])
|
||||
standyHat = mat(abx[100:199]) * standWs
|
||||
print "standRegress error Size is:", rssError(abY[100:199], standyHat.T.A)
|
||||
```
|
||||
|
||||
根据我们上边的测试,可以看出:
|
||||
|
||||
简单线性回归达到了与局部加权现行回归类似的效果。这也说明了一点,必须在未知数据上比较效果才能选取到最佳模型。那么最佳的核大小是 10 吗?或许是,但如果想得到更好的效果,应该用 10 个不同的样本集做 10 次测试来比较结果。
|
||||
|
||||
> 使用算法: 使用回归,可以在给定输入的时候预测出一个数值,这是对分类方法的提升,因为这样可以预测连续型数据而不仅仅是离散的类别标签
|
||||
|
||||
|
||||
### 4、缩减系数来 “理解” 数据
|
||||
|
||||
如果数据的特征比样本点还多应该怎么办?是否还可以使用线性回归和之前的方法来做预测?答案是否定的,即我们不能再使用前面介绍的方法。这是因为在计算  的时候会出错。
|
||||
|
||||
如果特征比样本点还多(n > m),也就是说输入数据的矩阵 x 不是满秩矩阵。非满秩矩阵求逆时会出现问题。
|
||||
|
||||
为了解决这个问题,我们引入了 `岭回归(ridge regression)` 这种缩减方法。接着是 `lasso法`,最后介绍 `前向逐步回归`。
|
||||
|
||||
#### 4.1、岭回归
|
||||
|
||||
简单来说,岭回归就是在矩阵  上加一个 λI 从而使得矩阵非奇异,进而能对  求逆。其中矩阵I是一个 m * m 的单位矩阵,
|
||||
对角线上元素全为1,其他元素全为0。而λ是一个用户定义的数值,后面会做介绍。在这种情况下,回归系数的计算公式将变成:
|
||||
|
||||

|
||||
|
||||
岭回归最先用来处理特征数多于样本数的情况,现在也用于在估计中加入偏差,从而得到更好的估计。这里通过引入 λ 来限制了所有 w 之和,通过引入该惩罚项,能够减少不重要的参数,这个技术在统计学中也叫作 `缩减(shrinkage)`。
|
||||
|
||||
缩减方法可以去掉不重要的参数,因此能更好地理解数据。此外,与简单的线性回归相比,缩减法能取得更好的预测效果。
|
||||
|
||||
这里通过预测误差最小化得到 λ: 数据获取之后,首先抽一部分数据用于测试,生育的作为训练集用于训练参数 w。训练完毕后在测试集上测试预测性能。通过选取不同的 λ 来重复上述测试过程,最终得到一个使预测误差最小的 λ 。
|
||||
|
||||
##### 4.1.1、岭回归 原始代码
|
||||
|
||||
```python
|
||||
def ridgeRegres(xMat,yMat,lam=0.2):
|
||||
'''
|
||||
Desc:
|
||||
这个函数实现了给定 lambda 下的岭回归求解。
|
||||
如果数据的特征比样本点还多,就不能再使用上面介绍的的线性回归和局部现行回归了,因为计算 (xTx)^(-1)会出现错误。
|
||||
如果特征比样本点还多(n > m),也就是说,输入数据的矩阵x不是满秩矩阵。非满秩矩阵在求逆时会出现问题。
|
||||
为了解决这个问题,我们下边讲一下:岭回归,这是我们要讲的第一种缩减方法。
|
||||
Args:
|
||||
xMat:样本的特征数据,即 feature
|
||||
yMat:每个样本对应的类别标签,即目标变量,实际值
|
||||
lam:引入的一个λ值,使得矩阵非奇异
|
||||
Returns:
|
||||
经过岭回归公式计算得到的回归系数
|
||||
'''
|
||||
|
||||
xTx = xMat.T*xMat
|
||||
# 岭回归就是在矩阵 xTx 上加一个 λI 从而使得矩阵非奇异,进而能对 xTx + λI 求逆
|
||||
denom = xTx + eye(shape(xMat)[1])*lam
|
||||
# 检查行列式是否为零,即矩阵是否可逆,行列式为0的话就不可逆,不为0的话就是可逆。
|
||||
if linalg.det(denom) == 0.0:
|
||||
print ("This matrix is singular, cannot do inverse")
|
||||
return
|
||||
ws = denom.I * (xMat.T*yMat)
|
||||
return ws
|
||||
|
||||
|
||||
def ridgeTest(xArr,yArr):
|
||||
'''
|
||||
Desc:
|
||||
函数 ridgeTest() 用于在一组 λ 上测试结果
|
||||
Args:
|
||||
xArr:样本数据的特征,即 feature
|
||||
yArr:样本数据的类别标签,即真实数据
|
||||
Returns:
|
||||
wMat:将所有的回归系数输出到一个矩阵并返回
|
||||
'''
|
||||
|
||||
xMat = mat(xArr)
|
||||
yMat=mat(yArr).T
|
||||
# 计算Y的均值
|
||||
yMean = mean(yMat,0)
|
||||
# Y的所有的特征减去均值
|
||||
yMat = yMat - yMean
|
||||
# 标准化 x,计算 xMat 平均值
|
||||
xMeans = mean(xMat,0)
|
||||
# 然后计算 X的方差
|
||||
xVar = var(xMat,0)
|
||||
# 所有特征都减去各自的均值并除以方差
|
||||
xMat = (xMat - xMeans)/xVar
|
||||
# 可以在 30 个不同的 lambda 下调用 ridgeRegres() 函数。
|
||||
numTestPts = 30
|
||||
# 创建30 * m 的全部数据为0 的矩阵
|
||||
wMat = zeros((numTestPts,shape(xMat)[1]))
|
||||
for i in range(numTestPts):
|
||||
# exp() 返回 e^x
|
||||
ws = ridgeRegres(xMat,yMat,exp(i-10))
|
||||
wMat[i,:]=ws.T
|
||||
return wMat
|
||||
|
||||
|
||||
#test for ridgeRegression
|
||||
def regression3():
|
||||
abX,abY = loadDataSet("input/8.Regression/abalone.txt")
|
||||
ridgeWeights = ridgeTest(abX, abY)
|
||||
fig = plt.figure()
|
||||
ax = fig.add_subplot(111)
|
||||
ax.plot(ridgeWeights)
|
||||
plt.show()
|
||||
```
|
||||
|
||||
##### 4.1.2、岭回归在鲍鱼数据集上的运行效果
|
||||
|
||||

|
||||
|
||||
上图绘制除了回归系数与 log(λ) 的关系。在最左边,即 λ 最小时,可以得到所有系数的原始值(与线性回归一致);而在右边,系数全部缩减为0;在中间部分的某值将可以取得最好的预测效果。为了定量地找到最佳参数值,还需要进行交叉验证。另外,要判断哪些变量对结果预测最具有影响力,在上图中观察它们对应的系数大小就可以了。
|
||||
|
||||
|
||||
#### 4.2、lasso
|
||||
|
||||
在增加如下约束时,普通的最小二乘法回归会得到与岭回归一样的公式:
|
||||
|
||||

|
||||
|
||||
上式限定了所有回归系数的平方和不能大于 λ 。使用普通的最小二乘法回归在当两个或更多的特征相关时,可能会得到一个很大的正系数和一个很大的负系数。正式因为上述限制条件的存在,使用岭回归可以避免这个问题。
|
||||
|
||||
与岭回归类似,另一个缩减方法lasso也对回归系数做了限定,对应的约束条件如下:
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
## 岭回归和逐步线性回归
|
||||
|
||||
BIN
images/8.Regression/LinearR_10.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
images/8.Regression/LinearR_11.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
images/8.Regression/LinearR_12.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
images/8.Regression/LinearR_13.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
images/8.Regression/LinearR_14.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
images/8.Regression/LinearR_2.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
images/8.Regression/LinearR_3.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
images/8.Regression/LinearR_4.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
images/8.Regression/LinearR_5.png
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
BIN
images/8.Regression/LinearR_6.png
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
images/8.Regression/LinearR_7.png
Normal file
|
After Width: | Height: | Size: 46 KiB |
BIN
images/8.Regression/LinearR_8.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
images/8.Regression/LinearR_9.png
Normal file
|
After Width: | Height: | Size: 683 B |
@@ -396,6 +396,41 @@ def regression2():
|
||||
plt.show()
|
||||
|
||||
|
||||
# test for abloneDataSet
|
||||
def abaloneTest():
|
||||
'''
|
||||
Desc:
|
||||
预测鲍鱼的年龄
|
||||
Args:
|
||||
None
|
||||
Returns:
|
||||
None
|
||||
'''
|
||||
# 加载数据
|
||||
abX, abY = loadDataSet("input/8.Regression/abalone.txt")
|
||||
# 使用不同的核进行预测
|
||||
oldyHat01 = lwlrTest(abX[0:99], abX[0:99], abY[0:99], 0.1)
|
||||
oldyHat1 = lwlrTest(abX[0:99], abX[0:99], abY[0:99], 1)
|
||||
oldyHat10 = lwlrTest(abX[0:99], abX[0:99], abY[0:99], 10)
|
||||
# 打印出不同的核预测值与训练数据集上的真实值之间的误差大小
|
||||
print "old yHat01 error Size is :" , rssError(abY[0:99], oldyHat01.T)
|
||||
print "old yHat1 error Size is :" , rssError(abY[0:99], oldyHat1.T)
|
||||
print "old yHat10 error Size is :" , rssError(abY[0:99], oldyHat10.T)
|
||||
|
||||
# 打印出 不同的核预测值 与 新数据集(测试数据集)上的真实值之间的误差大小
|
||||
newyHat01 = lwlrTest(abX[100:199], abX[0:99], abY[0:99], 0.1)
|
||||
print "new yHat01 error Size is :" , rssError(abY[0:99], yHat01.T)
|
||||
newyHat1 = lwlrTest(abX[100:199], abX[0:99], abY[0:99], 1)
|
||||
print "new yHat1 error Size is :" , rssError(abY[0:99], yHat1.T)
|
||||
newyHat10 = lwlrTest(abX[100:199], abX[0:99], abY[0:99], 10)
|
||||
print "new yHat10 error Size is :" , rssError(abY[0:99], yHat10.T)
|
||||
|
||||
# 使用简单的 线性回归 进行预测,与上面的计算进行比较
|
||||
standWs = standRegres(abX[0:99], abY[0:99])
|
||||
standyHat = mat(abx[100:199]) * standWs
|
||||
print "standRegress error Size is:", rssError(abY[100:199], standyHat.T.A)
|
||||
|
||||
|
||||
#test for ridgeRegression
|
||||
def regression3():
|
||||
abX,abY = loadDataSet("input/8.Regression/abalone.txt")
|
||||
|
||||