05.1 正规方程法
5.1 正规方程解法⚓︎
英文名是 Normal Equations。
对于线性回归问题,除了前面提到的最小二乘法可以解决一元线性回归的问题外,也可以解决多元线性回归问题。
对于多元线性回归,可以用正规方程来解决,也就是得到一个数学上的解析解。它可以解决下面这个公式描述的问题:
5.1.1 简单的推导方法⚓︎
在做函数拟合(回归)时,我们假设函数 \(H\) 为:
令 \(b=w_0\),则:
公式3中的 \(x\) 是一个样本的 \(n\) 个特征值,如果我们把 \(m\) 个样本一起计算,将会得到下面这个矩阵:
公式5中的 \(X\) 和 \(W\) 的矩阵形状如下:
然后我们期望假设函数的输出与真实值一致,则有:
其中,Y的形状如下:
直观上看,\(W = Y/X\),但是这里三个值都是矩阵,而矩阵没有除法,所以需要得到 \(X\) 的逆矩阵,用 \(Y\) 乘以 \(X\) 的逆矩阵即可。但是又会遇到一个问题,只有方阵才有逆矩阵,而 \(X\) 不一定是方阵,所以要先把左侧变成方阵,就可能会有逆矩阵存在了。所以,先把等式两边同时乘以 \(X\) 的转置矩阵,以便得到 \(X\) 的方阵:
其中,\(X^{\top}\) 是 \(X\) 的转置矩阵,\(X^{\top}X\) 一定是个方阵,并且假设其存在逆矩阵,把它移到等式右侧来:
至此可以求出 \(W\) 的正规方程。
5.1.2 复杂的推导方法⚓︎
我们仍然使用均方差损失函数(略去了系数\(\frac{1}{2m}\)):
把 \(b\) 看作是一个恒等于 \(1\) 的feature,并把 \(Z=XW\) 计算公式带入,并变成矩阵形式:
对 \(W\) 求导,令导数为 \(0\),可得到 \(W\) 的最小值解:
求导后(请参考矩阵/向量求导公式):
第一项的结果是:\(2X^{\top}XW\)(分母布局,denominator layout)
第二项的结果是:\(X^{\top}Y\)(分母布局方式,denominator layout)
第三项的结果是:\(X^{\top}Y\)(分子布局方式,numerator layout,需要转置\(Y^{\top}X\))
第四项的结果是:\(0\)
再令导数为 \(0\):
结论和公式10一样。
以上推导的基本公式可以参考第0章的公式60-69。
逆矩阵 \((X^{\top}X)^{-1}\) 可能不存在的原因是:
- 特征值冗余,比如 \(x_2=x^2_1\),即正方形的边长与面积的关系,不能作为两个特征同时存在;
- 特征数量过多,比如特征数 \(n\) 比样本数 \(m\) 还要大。
以上两点在我们这个具体的例子中都不存在。
5.1.3 代码实现⚓︎
我们把表5-1的样本数据带入方程内。根据公式(5),我们应该建立如下的 \(X,Y\) 矩阵:
根据公式(10):
- \(X\) 是 \(1000\times 3\) 的矩阵,\(X\) 的转置是 \(3\times 1000\),\(X^{\top}X\) 生成 \(3\times 3\) 的矩阵;
- \((X^{\top}X)^{-1}\) 也是 \(3\times 3\) 的矩阵;
- 再乘以 \(X^{\top}\),即 \(3\times 3\) 的矩阵乘以 \(3\times 1000\) 的矩阵,变成 \(3\times 1000\) 的矩阵;
- 再乘以 \(Y\),\(Y\)是 \(1000\times 1\) 的矩阵,所以最后变成 \(3\times 1\) 的矩阵,成为 \(W\) 的解,其中包括一个偏移值 \(b\) 和两个权重值 \(w\),3个值在一个向量里。
if __name__ == '__main__':
reader = SimpleDataReader()
reader.ReadData()
X,Y = reader.GetWholeTrainSamples()
num_example = X.shape[0]
one = np.ones((num_example,1))
x = np.column_stack((one, (X[0:num_example,:])))
a = np.dot(x.T, x)
# need to convert to matrix, because np.linalg.inv only works on matrix instead of array
b = np.asmatrix(a)
c = np.linalg.inv(b)
d = np.dot(c, x.T)
e = np.dot(d, Y)
#print(e)
b=e[0,0]
w1=e[1,0]
w2=e[2,0]
print("w1=", w1)
print("w2=", w2)
print("b=", b)
# inference
z = w1 * 15 + w2 * 93 + b
print("z=",z)
5.1.4 运行结果⚓︎
w1= -2.0184092853092226
w2= 5.055333475112755
b= 46.235258613837644
z= 486.1051325196855
我们得到了两个权重值和一个偏移值,然后得到房价预测值 \(z=486\) 万元。
至此,我们得到了解析解。我们可以用这个做为标准答案,去验证我们的神经网络的训练结果。
代码位置⚓︎
ch05, Level1