线性回归问题的思路:
x是由若干个feature组成的列向量,y是一个数值,代表根据feature预测出的结果(比如房价之类的)。
假设真实的y关于x的关系满足函数$y=F(\Theta^Tx)$,其中$\Theta$是与x相容的列向量,代表每个feature的权重。
F代表了从x映射到y的一个关系。
那么对于很多个x组成的矩阵X,和对应的结果Y,同样满足$Y=F(\Theta^TX)$,其中Y是与样本个数相容的行向量,代表每一个样本的预测结果。
定义损失函数:
$J(\Theta,X,Y)={\frac{1}{m}}\sum_{i=1}^{m}{\frac{(\Theta^{T}X^{i}-Y^{i})^2}{2}}$
$X^i$代表X的第i列,也就是第i个样本的feature。
由于X和Y是给定的,所以我们的目标是通过调整$\Theta$使得$J(\Theta,X,Y)$最小。
调整方法是通过求偏导,在J是有极小值的情况下,回归可以得到使得J取极小值的对应的$\Theta$。
J对第i个权重求偏导的结果:
$\frac{\partial J(\Theta)}{\partial \Theta_i}=\frac{1}{m}\sum_{j=1}^{m}(\Theta^TX^j-Y^j)*X^j_i$
通过不断迭代,使得$\Theta$不断向让J变小的趋势靠拢。
用Python代码实现如下(未经过任何优化):
1 import numpy as np 2 import matplotlib.pyplot as plt 3 from mpl_toolkits.mplot3d import Axes3D 4 5 6 def J(theta, X, Y): 7 m = Y.shape[1] 8 return (((theta.transpose().dot(X) - Y) ** 2).sum(axis=1) / (m * 2))[0] 9 10 11 def P_J(theta, X, Y): 12 m = Y.shape[1] 13 return ((theta.transpose().dot(X) - Y).dot(X.transpose()) / m).transpose() 14 15 16 def Generate(theta, m): 17 n = theta.shape[0] 18 X = (np.random.rand(n * m) * 100).reshape((n, m)) 19 Y = theta.transpose().dot(X) 20 return X, Y 21 22 23 def Learn(X, Y, alpha, cnt): # 以alpha的学习率学习cnt次 24 theta = np.zeros((X.shape[0] + 1, 1)) 25 XX = np.ones((X.shape[0] + 1, X.shape[1])) 26 XX[1:, :] = X 27 Jc = [] 28 while cnt > 0: 29 th = theta 30 Jc.append(J(theta, XX, Y)) 31 theta = th - alpha * P_J(theta, XX, Y) 32 cnt -= 1 33 plt.plot(Jc) 34 plt.title("J(θ) and the predict Y") 35 txt = "y=%.2f" % (theta[0]) 36 for i in range(1, XX.shape[0]): 37 txt += "+%.2fx_%d" % (theta[i], i) 38 plt.annotate(txt, xy=(10, 10), xytext=(10, 10)) 39 plt.show() 40 return theta 41 42 43 X, Y = Generate(np.array([[1], [2]]), 2000) # y = x1 + 2*x2 44 45 # 真实的(生成的)数据情况 46 fig = plt.figure() 47 ax = fig.add_subplot(111, projection='3d') 48 ax.scatter(X.transpose()[:, 0], X.transpose()[:, 1], Y.transpose()) 49 plt.show() 50 51 theta = Learn(X, Y, 0.00002, 200)
下面对原始的损失函数作适当修改:
$J(\Theta,X,Y)={\frac{1}{2m}}(\sum_{i=1}^{m}(\Theta^{T}X^{i}-Y^{i})^2+\lambda\sum_{i=1}^n\Theta_i^2)$
意思是说让每个参数都尽量小,这样在适当选取$\lambda$的情况下可以防止过拟合。但是如果加入一维bias的权重,这一维要单独处理,不正则化,具体原因还没想明白,不过好像影响不是很大。
对这个损失函数求偏导,就得到了:
$\frac{\partial J(\Theta)}{\partial \Theta_i}=\frac{1}{m}\sum_{j=1}^{m}(\Theta^TX^j-Y^j)*X^j_i+\frac{\lambda}{m}\Theta_i$
下面是对上面的代码稍作修改,得到的正则化的代码:
1 import numpy as np 2 import matplotlib.pyplot as plt 3 from mpl_toolkits.mplot3d import Axes3D 4 5 6 def J(theta, X, Y, lam): 7 m = Y.shape[1] 8 return ((((theta.transpose().dot(X) - Y) ** 2).sum(axis=1) + lam * (theta[1:] * theta[1:]).sum(axis=0)) / (m * 2))[ 9 0] 10 11 12 def P_J(theta, X, Y, lam): 13 m = Y.shape[1] 14 mat1 = ((theta.transpose().dot(X) - Y).dot(X.transpose()) / m).transpose() 15 mat2 = np.zeros(theta.shape) 16 mat2[1:] = (theta * lam / m)[1:] 17 return mat1 + mat2 18 19 20 def Generate(theta, m): 21 n = theta.shape[0] 22 X = (np.random.rand(n * m) * 100).reshape((n, m)) 23 Y = theta.transpose().dot(X) 24 return X, Y 25 26 27 def Learn(X, Y, alpha, lam, cnt): # 以alpha的学习率学习cnt次 28 theta = np.zeros((X.shape[0] + 1, 1)) 29 XX = np.ones((X.shape[0] + 1, X.shape[1])) 30 XX[1:, :] = X 31 Jc = [] 32 while cnt > 0: 33 th = theta 34 Jc.append(J(theta, XX, Y, lam)) 35 theta = th - alpha * P_J(theta, XX, Y, lam) 36 cnt -= 1 37 plt.plot(Jc) 38 plt.title("J(θ) and the predict Y") 39 txt = "y=%.2f" % (theta[0]) 40 for i in range(1, XX.shape[0]): 41 txt += "+%.2fx_%d" % (theta[i], i) 42 plt.annotate(txt, xy=(10, 10), xytext=(10, 10)) 43 plt.show() 44 return theta 45 46 47 X, Y = Generate(np.array([[500], [0]]), 2000) # y = x1 + 2*x2 48 49 # 真实的(生成的)数据情况 50 fig = plt.figure() 51 ax = fig.add_subplot(111, projection='3d') 52 ax.scatter(X.transpose()[:, 0], X.transpose()[:, 1], Y.transpose()) 53 plt.show() 54 55 theta = Learn(X, Y, 0.00002, 100, 2000)