优点:结果易于理解,计算上不复杂
缺点:对非线性的数据拟合不好
线性回归
用于数值预测,回归方程为
写成矩阵形式
为方便计算,添加 , 取 , 将式子改写为
采用平方差做损失函数
用矩阵表示为
其中 X 是 (m,n) 矩阵,W 是 (n,1) 矩阵,Y 是 (m,1) 矩阵
对 求导
另导数为 0 得到最优的
代码
def standRegres(xArr, yArr):
"""
xArr - 样本特征,是 (m,n) 矩阵,每行的第一个值既 X0 固定为 1
yArr - 样本标签,是 (1,m)
"""
xMat = np.mat(xArr)
yMat = np.mat(yArr).T
xTx = xMat.T * xMat
if np.linalg.det(xTx) == 0.0:
# 如果行列式等于 0,意味着没有逆矩阵
return None
# 也可以用 ws = np.linalg.solve(xTx, xMat.T*yMat)
w = xTx.I * xMat.T * yMat
# ws 是 (n,1) 矩阵
return w
通过相关系统判断效果好坏
# 结果越接近 1 效果越好
np.corrcoef(yEstimate, yActual)
局部加权线性回归 (Locally Weighted Linear Regression,LWLR)
线性回归的一个问题是有可能出现欠拟合现象,就是偏离拟合曲线的点比较多
与此对应的有过拟合问题,就是拟合曲线过于迎合数据点,这意味着曲线被噪点干扰比较大
解决欠拟合问题的一个方法是局部加权线性回归
给待预测点附近的每个点赋予权重,然后在这个子集上基于最小均方差进行普通的回归
注意:与 kNN 一样,这种算法每次预测均需要事先选取出对应的数据子集
LWLR 使用核函数来对附近的点赋予权重,核的类型可以自由选择,常用的是高斯核
只含对角元素的矩阵,x 是测试点,xi 与 x 越近权重越大,k 越大权重越大,权值必然小于 1
k 越大越容易欠拟合,越小越容易过拟合
算法如下
代码
def lwlr(testPoint, xArr, yArr, k=1.0):
"""
testPoint - 待预测的点 (1,n)
xArr - 样本特征 (m,n),每个样本的第一个值既 X0 固定为 1
yArr - 样本标签 (1,m)
"""
xMat = np.mat(xArr)
yMat = np.mat(yArr).T
m = np.shape(xMat)[0]
# eye 是单位矩阵,对角线是 1,其余是 0
weights = np.mat(np.eye(m))
# 遍历所有数据
for j in range(m):
# 计算权重
diffMat = testPoint - xMat[j, :]
weights[j, j] = np.exp(diffMat * diffMat.T / (-2.0 * k ** 2))
xTx = xMat.T * (weights * xMat)
if np.linalg.det(xTx) == 0.0:
# 如果行列式等于 0,意味着没有逆矩阵
return
# 得出回归系数 (n,1)
w = xTx.I * (xMat.T * (weights * yMat))
return testPoint * w
缩减法
如果数据的特征比样本点还多,则不能再使用前面的方法,因为在计算逆矩阵时会出错
岭回归
岭回归最先用来处理特征数多于样本数的情况
现在也用于在估计中加入偏差,从而得到更好的估计
为 加上 使得矩阵可逆,其中 r 是用户定义的数值,I 是单位矩阵
回归系数
代码
def ridgeRegres(xMat, yMat, lam=0.2):
"""
xMat - 样本特征 (m,n),每个样本的第一个值既 X0 固定为 1
yMat - 样本标签 (1,m)
"""
xTx = xMat.T * xMat
# 加上 r*I 使得矩阵可逆
denom = xTx + np.eye(np.shape(xMat)[1]) * lam
if np.linalg.det(denom) == 0.0:
return
w = denom.I * (xMat.T * yMat)
return w
def ridgeTest(xArr, yArr):
"""
xArr - 样本特征 (m,n),每个样本的第一个值既 X0 固定为 1
yArr - 样本标签 (1,m)
"""
xMat = np.mat(xArr)
yMat = np.mat(yArr).T
# Y 数据标准化,减去均值
yMean = np.mean(yMat, 0)
yMat = yMat - yMean
# X 数据标准化,减去均值,除以方差
xMeans = np.mean(xMat, 0)
xVar = np.var(xMat, 0)
xMat = (xMat - xMeans) / xVar
numTestPts = 30
# 初始化回归系数矩阵,每行是一次迭代产生的回归系数
wMat = np.zeros((numTestPts, np.shape(xMat)[1]))
for i in range(numTestPts):
# 迭代,尝试不同的 r 参数
ws = ridgeRegres(xMat, yMat, np.exp(i - 10))
wMat[i, :] = ws.T
# 返回所有回归系数,为了定量地找到最佳参数值,还需要进行交叉验证
# 一般讲,r 很小时就和普通回归系数一样,r 很大时回归系数趋向于 0
return wMat
lasso 方法
限制所有回归系数的绝对值的和必须小于某个值
前向逐步回归
属于一种贪心算法,每步尽可能减少误差
一开始所有的权重都设为 1,然后每步所做的决策是对某个权重增加或减少一个很小的值
前向逐步回归算法可以得到与 lasso 差不多的效果,但更加简单
代码
def stageWise(xArr, yArr, step=0.01, numIt=100):
"""
xArr - 样本特征 (m,n),每个样本的第一个值既 X0 固定为 1
yArr - 样本标签 (1,m)
step - 步长
numIt - 迭代次数
"""
xMat = np.mat(xArr)
yMat = np.mat(yArr).T
# Y 数据标准化,减去均值
yMean = np.mean(yMat, 0)
yMat = yMat - yMean
# X 数据标准化,减去均值,除以方差
xMeans = np.mean(xMat, 0)
xVar = np.var(xMat, 0)
xMat = (xMat - xMeans) / xVar
m, n = np.shape(xMat)
# 初始化回归系数矩阵,每行是一次迭代产生的回归系数
returnMat = np.zeros((numIt, n))
ws = np.zeros((n, 1))
wsMax = ws.copy()
# 迭代
for i in range(numIt):
lowestError = np.inf
# 每个系数
for j in range(n):
# 每个方向
for sign in [-1, 1]:
wsTest = ws.copy()
# 在上一次迭代产生的系数向量的基础上,按指定的步长、指定的方向,调整指定的系数
wsTest[j] += step * sign
# 预测结果
yTest = xMat * wsTest
# 计算方差
rssE = ((yMat.A - yTest.A) ** 2).sum()
# 效果更好则保存该系数
if rssE < lowestError:
lowestError = rssE
wsMax = wsTest
# 得到本次迭代的最佳系数
ws = wsMax.copy()
# 保存该最佳系数
returnMat[i, :] = ws.T
# 返回结果
return returnMat
网友评论