目录
什么是线性回归?
我小学二年级的妹妹想用压岁钱买房子,售楼广告上写着100万可以买100的房子,200万可以买200的房子,但是我的妹妹觉得那些房子都太小了,想买300的房子,那她应该要花多少钱呢?
对于这个问题,我们可以根据已知数据画出一条优美的直线,并且可以把直线方程求出来,根据这个直线方程就可以把房价和房子的面积映射起来。
求出该问题的直线方程就是线性回归的一个过程,在数学上通常叫做线性拟合。上述问题似乎很简单,但实际上我们已知的数据量是非常大的,而且涉及到的变量也非常多,通常需要用到最小二乘法或者梯度下降法去求解。
线性回归是一种数据分析技术,它通过使用另一个相关的已知数据值来预测未知数据的值。它以数学方式将未知变量或因变量以及已知变量或自变量建模为线性方程。
线性模型
要想理解这部分内容,需要懂一点我们小学学过的线性代数。
线性方程一般是这样写的:
但是变量太多的话,我们也可以用向量的形式去简写:
其中表示的估计值,是权重,是偏置,这就是一个线性模型,我们的最终目标就是把线性模型的这些参数求解出来。
在幼儿园的时候,我们经常用来表示二维平面上的直线,其中就是权重,就是偏置,有些人觉得用来表示会比较变扭,所以特此说明一下。
损失函数
损失函数其实就是用来描述我们画出来的直线是否合适,如果我们拟合的这条直线非常不合适,损失函数算出来的值就非常大,反之则值非常小。
回归问题中最常用的损失函数是平方误差函数:
如果估计出来的和实际值相等,也就是一点误差都没有,那损失函数的值就是0,这是最完美的一种情况。
如何解出线性模型?
线性回归是机器学习中的一个算法,通常我们解方程都是自己去解,但是如果该线性模型的参数太多了,我们就无法通过人去解决问题了。
这时候我们就要训练机器,让机器帮我们解决问题。但是机器如何解决这个问题?教机器去做这件事似乎十分的奇妙,接下来让我们深入了解一下吧!
上图是一组关于人口和收益的数据散点图,我们现在需要构建一个线性模型。那我们如何知道这个线性模型是否构建的很好呢?当然是最小化损失函数啦!
我们将损失函数与线性模型方程联系起来:
我们使得损失函数的值最小,那么得到的线性模型也就是最优的!
其中和表示它们的最优值。
最小二乘法
我们可以通过最小二乘法来对参数和进行估计。
现在把吸收到向量中,,其中就相当于是。
写成向量的形式就是将 变为 ,其中 。
综上可得:
要使得最小化,就是对求偏导为0,这涉及到矩阵的求导知识。
根据矩阵的性质 ,可得:
对求偏导可得:
令上式偏导为0,可以解得:
以上是公式的推导过程,最小二乘法适用于小数据量的线性模型,如果数据量太大,矩阵的逆会很难算出来,因为计算机对矩阵求逆的时间复杂度是。并且最小二乘法只适用于线性模型,不适合逻辑回归模型等其他模型。
最小二乘法算法实现:
python
def LSM(X, y):
# 计算矩阵X的转置与X相乘,再求逆矩阵,最后将结果与X的转置相乘,再与向量y相乘,得到权重w
w = np.linalg.inv(X.T@X)@X.T@y#X.T@X等价于X.T.dot(X)
return w
梯度下降法
梯度下降法是一个迭代算法,就像我们下山一样,我们想要以最快的速度到达山底,那我们就要往最陡峭的方向下山,每走米后就重新计算一下坡度,然后继续朝着最陡峭的方向下山。
而函数的梯度,在意义上就是变化率最大的方向。
上文最小二乘法的权重用表示,即:
。
这里的梯度下降法,我们为了和上图匹配,将权重用表示,即:
也可写成:
我们需要注意这里的是一个向量。
我们结合损失函数,即:
其中 是为了计算方便,求导后可以消除掉二次方的系数, 可以抵消掉数据量造成的影响,在目标函数加入 不影响最终结果的求解。
用梯度下降法求解参数,即:
其中 称为步长或者学习率,就像爬山走多少米测一次坡度一样,一般设置为0.01。学习率过小容易造成算法时间复杂度过高,学习率过大可能会导致在最优值附近"跳跃"。
通过梯度下降算法不断迭代即可求出全局最优解,我们对上述人口收益问题进行线性回归,可以得到下图:
批量梯度下降算法实现:
python
def batch_gradientDescent(X, y, w, alpha, count):
"""
参数:
X -- 特征矩阵,形状为 (n_samples, n_features)
y -- 标签向量,形状为 (n_samples,1)
w -- 权重向量,形状为 (n_features,1)
alpha -- 学习率
count -- 迭代次数
返回值:
w -- 更新后的权重向量
costs -- 每次迭代的代价函数值列表
"""
# 初始化代价函数值列表
costs = []
# 对每个样本进行迭代
for i in range(count):
# 根据公式更新权重向量
w = w - (X.T @ (X @ w - y)) * alpha / len(X)
# 计算当前代价函数值并添加到列表中
cost = computeCost(X, y, w)
costs.append(cost)
# 每隔100次迭代输出一次当前代价函数值
if i % 100 == 0:
print("在第{}次迭代中,cost的值是:{}。".format(i, cost))
# 返回最终的权重向量和代价函数值列表
return w, costs
梯度下降算法还有:随机梯度下降算法、小批量梯度下降算法,本质上就是拿部分的数据量去梯度下降,所以适用于数据量非常大的情况下,这里不过多赘述,有兴趣的小伙伴可以自行搜索。
局部加权线性回归
当数据分布呈曲线时,上述的方法不能很好的解决,如下图所示。在这种情况下,将使用局部加权线性回归。
局部加权线性回归,和微积分的一些思想很像,在一小区间内,直线是可以贴合曲线的。该模型不会像普通线性回归那样学习一组固定的参数。相反, 参数是为每个单独计算的。
在计算时,训练集中位于附近的点的"优先级"高于远离 的点。修改后的成本函数为:
其中, 是与训练点关联的非负 "权重" 。靠近的 越大否则越小。
典型选择下列函数计算权重:
注意:对于局部加权线性回归,数据必须始终在计算机上可用,因为它不会一次性从整个数据集中学习。而在线性回归中,训练模型后,可以从机器中删除训练集,因为模型已经学习了所需的参数。
构建目标函数:
利用最小二乘法,可以计算出一个θ向量(一个预测点对应一个向量θ):
局部线性回归算法:
python
def lwlr(testPoint,xArr,yArr,k=1.0):
xMat = np.mat(xArr); yMat = np.mat(yArr).T
m = np.shape(xMat)[0]
weights = np.mat(np.eye((m)))
for j in range(m): #next 2 lines create weights matrix
diffMat = testPoint - xMat[j,:] #difference matrix
weights[j,j] = np.exp(diffMat*diffMat.T/(-2.0*k**2)) #weighted matrix
xTx = xMat.T * (weights * xMat)
if np.linalg.det(xTx) == 0.0:
print ("This matrix is singular, cannot do inverse")
return
ws = xTx.I * (xMat.T * (weights * yMat)) #normal equation
return testPoint * w
结语
本人才疏学浅,文章难免会有错误之处,如遇错误恳请大家能够指出,不胜感激!
相关参考:
Stanford CS229: Machine Learning Andrew Ng
《机器学习初步》周志华