线性回归能做什么
分类的目标变量是标量,线性回归的目的是预测数值型的目标值,要掌握以下技术:
- 局部平滑技术
- 更好的拟合数据
- 回归在欠拟合状态下的缩减(shrinkage)
- 偏差和方差的概念
线性回归找最佳拟合直线
先明白几个概念
- regression equation:形如y = w1x1 + w2x2
- regression weights:w1和w2
- 什么叫回归:求w1和w2的过程
- 如何做预测:求出regression weights之后,用回归系数乘以输入值,将结果加在一起,就得到预测值。
回归的一般方法
- 收集数据:采用任意方法收集数据。
- 准备数据:回归需要数值型数据,标称型数据将被转成二值型数据。
- 分析数据:绘出数据的可视化二维图将有助于对数据做出理解和分析,在采用缩减法求得新回归系数之后,可以将新拟合线绘在图上作为对比。
- 训练算法:找到回归系数。
- 测试算法:使用R2或者预测值和数据的拟合度,来分析模型的效果。
- 使用算法:使用回归,可以在给定输入的时候预测出一个数值,这是对分类方法的提升,因为这样可以预测连续型数据而不仅仅是离散的类别标签。
核心问题在于如何找出回归系数w?一个常用的方法是,找出使误差最小的w,误差是指预测y值和真实y值之间的差距。我们不能将所有的差距相加,因为这些差距有正有负,而应该统一平方后再累加。
平方误差为:
regression.py
from numpy import *
def loadDataSet(fileName):
numFeat = len(open(fileName).readline().split('\t')) - 1
dataMat = []
labelMat = []
fr = open(fileName)
for line in fr.readlines():
lineArr = []
curLine = line.strip().split('\t')
for i in range(numFeat):
lineArr.append(float(curLine[i]))
dataMat.append(lineArr)
labelMat.append(float(curLine[-1]))
return dataMat,labelMat
def standRegress(xArr,yArr):
xMat = mat(xArr)
yMat = mat(yArr).T
xTx = xMat.T * xMat
if linalg.det(xTx) == 0.0:
print("this matrix is singular,can not do inverse")
return
ws = xTx.I * (xMat.T*yMat)
return ws
main.py
import regression
from numpy import *
import matplotlib.pyplot as plt
xArr,yArr = regression.loadDataSet('ex0.txt') #xArr二维列表,yArr是一维列表
ws = regression.standRegress(xArr, yArr) #求回归系数ws
xMat = mat(xArr) #转换为矩阵
yMat = mat(yArr)
yHat = xMat*ws #求出预测值
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(xMat[:, 1].flatten().A[0], yMat.T[:, 0].flatten().A[0])
xCopy = xMat.copy()
xCopy.sort(0)
yHat = xCopy*ws
ax.plot(xCopy[:, 1], yHat)
plt.show()
新建一个regression.py文件,导入numpy模块,在文件中定义两个函数,一个用于导入数据集,参数为文件名,另一个standRegress用来计算最佳拟合直线。
Python split()方法 | 菜鸟教程 (runoob.com)
Python strip()方法 | 菜鸟教程 (runoob.com)
python中mat()函数
Python numpy linalg.det用法及代码示例
Matplotlib Pyplot | 菜鸟教程 (runoob.com)
python - 在Matplotlib中,参数在fig.add_subplot(111)中意味着什么? - ITranslater
Python中scatter函数参数详解
Python中scatter函数参数详解
[python中flatten().A[0],中A[0]是干啥的]
(https://ask.csdn.net/questions/714188)
最后,我们会看到下面这个效果图
几乎所有的数据集都能用以上这个方法建立模型,但是如何比较预测数据yhat与真实数据y的匹配程度呢?我们可以用这两个值的相关系数来评价。
在Python中,NumPy库提供了相关系数的计算方法:可以通过命令corrcoef(yEstimate, yActual)来计算预测值和真实值的相关性。下面我们就在前面的数据集上做个实验。
测试函数
import matplotlib.pyplot as plt
from numpy import *
import regression
xArr,yArr = regression.loadDataSet('ex0.txt') #xArr二维列表,yArr是一维列表
ws = regression.standRegress(xArr, yArr) #求回归系数ws
xMat = mat(xArr) #转换为矩阵
yMat = mat(yArr)
yHat = xMat*ws
print(corrcoef(yHat.T, yMat))
该矩阵包含所有两两组合的相关系数。可以看到,对角线上的数据是1.0,因为yMat和自己的匹配是最完美的,而YHat和yMat的相关系数为0.98。
我们从以上图片可以看出,数据点走向不应该是一条直线,我们按上述方法找到的最佳拟合直线也是欠拟合的,因此我们还应该进一步细化直线走势——局部加权线性函数
局部加权线性回归
线性回归的一个问题是有可能出现欠拟合现象,因为它求的是具有最小均方误差的无偏估计什么是无偏估计?
模型欠拟合将不会获得好的预测效果,如果我们允许引入一些偏差,可能会更进一步降低均方误差。
引入局部加权线性回归LWLR
给预测点附近的每个点一个权重,在这个子集上基于最小均方误差来进行普通的回归
regression.py
from numpy import *
def loadDataSet(fileName):
numFeat = len(open(fileName).readline().split('\t')) - 1
dataMat = []
labelMat = []
fr = open(fileName)
for line in fr.readlines():
lineArr = []
curLine = line.strip().split('\t')
for i in range(numFeat):
lineArr.append(float(curLine[i]))
dataMat.append(lineArr)
labelMat.append(float(curLine[-1]))
return dataMat, labelMat
def lwlr(testPoint, xArr, yArr, k=1.0):
xMat = mat(xArr)
yMat = mat(yArr).T
m = shape(xMat)[0]
weights = mat(eye((m)))
for j in range(m):
diffMat = testPoint - xMat[j, :]
weights[j, j] = exp(diffMat * diffMat.T / (-2.0 * k ** 2))
xTx = xMat.T * (weights * xMat)
if linalg.det(xTx) == 0.0:
print("this matrix is singular,can not do inverse")
return
ws = xTx.I * (xMat.T * (weights * yMat))
return testPoint * ws
def lwlrTest(testArr, xArr, yArr, k=1.0):
m = shape(testArr)[0]
yHat = zeros(m)
for i in range(m):
yHat[i] = lwlr(testArr[i], xArr, yArr, k)
return yHat
在这里解释一些函数的意义:
python: numpy--函数 shape和eye用法
numpy库函数:zeros用法
main.py
import regression
from numpy import *
import matplotlib.pyplot as plt
xArr, yArr = regression.loadDataSet('ex0.txt')
yHat = regression.lwlrTest(xArr, xArr, yArr, 0.003)
xMat = mat(xArr)
srtInd = xMat[:, 1].argsort(0)
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()
局部加权线性回归增加了计算量,对每个点的预测都必须使用整个数据集,当k = 0.01时,大多数数据点的权重为0,减少了程序的运行时间。
缩减系数来“理解”数据
如果数据的特征点比样本点还多应该怎么办?这种情况下,计算XTX会等于0,即不可逆,因此会出错。
为了解决这个问题,引入两个缩减系数的方法:
- 岭回归(ridge regression)
- 前向逐步回归
1 岭回归
岭回归就是在XTX上加一个lam*I,矩阵I是一个单位矩阵,lam是用户自定义的。
缩减方法可以去掉不重要的参数,更好的理解数据,缩减法能取得更好的预测效果。
这里通过预测误差最小化得到lam。数据获取之后,一部分用于测试,剩下的作为训练集训练参数w,训练完毕之后在测试集上测试性能,选取不同的lam重复上述测试过程,最终得到一个使预测误差最小的lam。
def ridgeRegres(xMat, yMat, lam=0.2):
xTx = xMat.T * xMat
denom = xTx + eye(shape(xMat)[1]) * lam
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):
xMat = mat(xArr)
yMat = mat(yArr).T
yMean = mean(yMat, 0)
yMat = yMat - yMean # to eliminate X0 take mean off of Y
# regularize X's
xMeans = mean(xMat, 0) # calc mean then subtract it off
xVar = var(xMat, 0) # calc variance of Xi then divide by it
xMat = (xMat - xMeans) / xVar
numTestPts = 30
wMat = zeros((numTestPts, shape(xMat)[1]))
for i in range(numTestPts):
ws = ridgeRegres(xMat, yMat, exp(i - 10))
wMat[i, :] = ws.T
return wMat
main
import regression
from numpy import *
import matplotlib.pyplot as plt
abX, abY = regression.loadDataSet('abalone.txt')
ridgeWeights = regression.ridgeTest(abX, abY)
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(ridgeWeights)
plt.show()
运行之后的效果图如下:
在最左边,lam最小时,得到所有系数的原始值,而在最右边,系数全部缩减为0,在中间某部分的某值将会取得最好的预测效果,为了找到最佳参数值,还需要交叉验证。
2 前向逐步回归
lasso法对回归系数做了限定,对应的约束条件如下:
在lam足够小的时候,一些系数会被迫缩减为0,这个特性可以帮助我们理解数据,这个算法的计算复杂度相当高,我们采取一个更简单的办法来得到结果——前向逐步回归。
前向逐步回归更简单,属于贪心算法,每一步都尽可能减少误差。一开始,所有的权重都设置为1,然后每一步所做的决策是对某个权重增加或者减少一个很小的值。
逐步线性回归算法的实际好处在于它可以帮助人们理解现有的模型并做出改进。构建了这个模型之后,可以运行该算法找到重要的特征,可以及时停止对不重要特征的收集。如果用于测试,该算法每100次迭代后,就可以构建一个模型,可以使用10折交叉验证的方法比较这些模型,最终选择使误差最小的模型。
当应用缩减方法时,模型也就增加了偏差,与此同时却减小了模型的方差。
3 权衡偏差与方差
-
误差:模型和测量值之间的差异
我们在建立模型时,可能会对复杂的过程进行简化,这将导致在模型和测量值之间出现噪声或者误差。
偏差方差折中与测试误差及训练误差的关系
我们已经知道,如果降低核的大小,训练误差将缩小。
一般认为,测试误差及训练误差由三部分组成:偏差、测量误差和随机噪声。