已有知识:
- 线性回归(统计学)
- 线性回归(机器学习)
回归问题简单说就是给出一组特征,模型需要给出一个回答,这个回答是个连续的数值,也就是说模型的输出应该是个实数。
因此回归问题的模型是一个实函数。
线性回归则是用线性函数 来建立模型。
写成向量形式就是(一维向量均是列向量):
回归本身是个估计问题,没有对错之分,所以需要一个评价标准来评价一个回归模型的好坏。常见的评价标准有MSE,SAE,SSE等
误差度量标准 | 优缺点 |
---|---|
SSE(误差平方和) | 样本多时数值会累加到很大, 处理起来不便 |
SAE(绝对误差和) | 绝对值性质很差,难以进行数学运算 |
MSE(均方误差) | 数值不爆炸,数学性质好(凸性) |
记训练集第个样本为
, 对应标签为
因此,此处选择MSE作为模型好坏的度量标准。
于是问题转化为优化问题:
要求多元函数的最小值,一个必要不充分条件是求出某点使得其各个方向偏导数均为零,又由于这个函数性质良好(参见凸优化相关内容),于是这就成了充要条件。因此根据这个条件可以求得方程组并且解之,实际上一元的线性回归就是这么做的,初中课本上还有一元线性回归的公式,多元的情况类似,但是运算更复杂,在此不赘述。
为了简化运算,将式写成完全的矩阵形式:
根据线性代数的结论,倘若有n个样本, label对应为,上式成为
其中为:
为:
参见wikipedia,或者其他文献,keywords:广义逆矩阵
它的误差的二范数(就是MSE)极小的解为。
是
的广义逆矩阵。
首先导入需要用到的库:
import numpy as np
# This import registers the 3D projection, but is otherwise unused.
from mpl_toolkits.mplot3d import Axes3D # noqa: F401 unused import
import matplotlib.pyplot as plt
import numpy as np
然后随机生成一些数据作为样本集:
#特征数量和样本数量
feature_num = 2
num_examples = 100
#预设的w和b
preset_w =np.array([2.2, 7.5])
preset_b = 2.8
#假数据
fake_data_X = np.random.rand(num_examples, feature_num)
#通过预设的w和b算出对应的labels
labels = fake_data_X.dot( preset_w.reshape(2,1) )+ preset_b
#给labels加个随机误差
labels += np.random.normal(loc=0, scale=0.01,size=(num_examples, 1))
#开始训练模型
#对应上述几个公式来看
#
fake_data_X_with_one = np.column_stack( (fake_data_X, np.ones((num_examples, 1))) )
persudo_invert_X_with_one = np.linalg.pinv(fake_data_X_with_one)
model_params = persudo_invert_X_with_one.dot(labels)
#输出模型参数
model_params
array([[2.20471427],
[7.50252716],
[2.79889165]])
对比可以发现算出的模型参数和预设值相差不算太大。
绘制一下原始数据和回归结果的图形直观感受一下:
![](https://img.haomeiwen.com/i1349214/0c9c135fa34d5c7a.png)
这3D图太难操作了,画出来还这么抽象........可以看到我们的样本点分布在回归曲面的附近就够了。
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.scatter(fake_data_X[:,0], fake_data_X[:,1], labels, color='r')
u = np.linspace(0, 1, 15)
v = np.linspace(0, 1, 15)
x, y = np.meshgrid(u, v )
xy1 = np.column_stack((x.reshape(15*15, 1), y.reshape(15*15, 1), np.ones((15*15, 1)) ))
#通过模型算出回归结果
z = x*model_params[0] + y*model_params[1] + model_params[2]
ax.plot_surface(x, y , z , alpha=0.5, color='b')
ax.view_init(elev=15,
azim=45 )
plt.show()
![](https://img.haomeiwen.com/i1349214/b0962e49614dfd98.png)
可以看到计算的结果和我们预设的值非常接近。可见我们的结果是有效的。
有些读者肯定不服了,你这怕是是假机器学习,直接用公式就算出来了也算数?训练过程呢?梯度下降呢?
这种方法的确和现代机器学习的原理大相径庭,它通过数学原理直接算出了模型需要的参数,但是它的缺陷也是显然的:它需要所有的数据来参与运算,如果有新的数据到来,它只能推倒重算,无法利用已有的结果。另外它只适用于性质很好(在数学领域研究透彻了)的函数。
作为入门的第一课,我只是想借助这个例子说明机器学习的本质:
你假设一个模型 能够解决问题,但是参数
是未知的,你只要用某种方法求得一个误差可接受的参数
即可。
如果使用成熟的机器学习框架来训练,它的结果会是多少呢?
from sklearn import linear_model
#创建一个随机梯度下降的线性回归模型并且训练
regress = linear_model.SGDRegressor(max_iter=2000)
regress.fit(fake_data_X, labels.reshape(1,num_examples)[0])
#输出训练结果
print("线性模型系数W为", regress.coef_)
print("线性模型常数项b为", regress.intercept_)
线性模型系数W为 [2.20029992 7.49111373]
线性模型常数项b为 [2.80727725]
可以看出,随机梯度下降法(SGD)在迭代2000次的情况下得到了一个还算精确的结果。
ref:
[1] 监督学习-线性模型(sklearn)
网友评论