线性回归算法
和knn算法不同,线性回归算法主要用于解决回归问题,它同样思想简单,实现容易,而且是许多强大的非线性模型(如SVM)的基础。
线性回归的结果具有很好的可解释性,蕴含机器学习中很多重要的思想。因此线性回归也是非常重要的机器学习算法。
以一个房价预测为例,来说明什么是线性回归:
在该例子中,线性回归算法认为房价和房屋面积存在一定的线性关系,于是为了更好地描述模型,需要寻找一条直线,这条直线能最大程度拟合样本特征和样本输出标记之间的关系。在本例子中只有一个特征即房屋面积,输出标记为价格。如果有两个特征则需要在三维坐标系中画图,如果有更多特征则需要更高维度空间。为了可视化方便,本文将都以一个特征为例进行讲解。
对于样本特征只有一个的线性回归,我们称之为简单线性回归,对于多个特征的线性回归可以由简单线性回归进行推广。
在房价的例子中,如果我们找到了这条拟合直线,那么之后如果知道了房屋面积就可以进行房价的预测。
于是,我们希望真实的与的差距尽量小,考虑所有的样本,他们的差距表示为:
将带入,我们的目标就是想办法找到参数a和b让差距尽可能小。这个差距称之为损失函数(loss function)。
这也是机器学习算法的基本思路,模型要尽可能拟合数据,使输出与真实数据差距最小。有时会使用评价拟合程度的函数,称之为效用函数(utility function),这个则要越大越好。不管如何,都是通过分析问题确定问题的损失函数或者效用函数,通过最优化损失函数或者效用函数,获得机器学习的模型。近乎所有参数学习算法都是这样的套路。区别就在于要优化的目标函数不同(线性回归,多项式回归,SVM,NN...)。有一门与机器学习相关的《最优化原理》(运筹学)课程就是探讨最优理论的,有兴趣的可以查阅学习一下。
回到上面的线性回归问题,这是一个典型的最小二乘法问题,最小化误差的平方。在数学上可以用Lagrange乘数法很简单地求得最优的a和b,这里直接给出他们的表达式:
实现Simple Linear Regression
使用模拟数剧集来实现线性回归。
import numpy as np
import matplotlib.pylab as plt
x=np.array([1,2,3,4,5],dtype=float)
y=np.array([1,3,2,3,5],dtype=float)
plt.scatter(x,y)
plt.axis([0,6,0,6])
plt.show()
模拟数据
'''计算a和b'''
x_mean = np.mean(x)
y_mean = np.mean(y)
num = 0.0
d = 0.0
for x_i,y_i in zip(x,y):
num += (x_i-x_mean)*(y_i-y_mean)
d += (x_i-x_mean)**2
a = num/d
b = y_mean - a*x_mean
'''画出线性回归拟合直线'''
plt.scatter(x,y)
plt.plot(x,y_hat,color='r')
plt.axis([0,6,0,6])
plt.show()
拟合直线
a和b
下面进行类似sklearn的算法封装,在play_Ml中新建SimpleLinearRegression.py,代码如下:
import numpy as np
class SimpleLinearRegression1:
def __init__(self):
'''初始化简单线性回归模型'''
self.a_ = None
self.b_ = None
def fit(self,x_train,y_train):
'''训练模型'''
assert x_train.ndim == 1,"one feature!"
assert len(x_train) == len(y_train),"size must be the same!"
x_mean = np.mean(x_train)
y_mean = np.mean(y_train)
num = 0.0
d = 0.0
for x_i,y_i in zip(x_train,y_train):
num += (x_i-x_mean)*(y_i-y_mean)
d += (x_i-x_mean)**2
self.a_ = num/d
self.b_ = y_mean - self.a_*x_mean
return self
def predict(self,x_predict):
'''给定待预测数剧集x_predict,返回结果向量'''
assert x_predict.ndim == 1,"one feature!"
assert self.a_ is not None and self.b_ is not None,"fit first!"
return np.array([self._predict(x) for x in x_predict])
def _predict(self,x_single):
'''给定单个待预测数据,返回预测结果'''
return self.a_*x_single+self.b_
def __repr__(self):
return "SimpleLinearRegression1()"
使用我们的算法:
ownLog
可以发现得到的和上面是一样的结果。
向量化运算提升算法性能
上面计算a和b时,使用for循环是最基本的复合逻辑的算法,不过考虑到numpy模块可以进行向量化运算加快运算速度,可以做如下修改:
def fit(self,x_train,y_train):
'''训练模型'''
assert x_train.ndim == 1,"one feature!"
assert len(x_train) == len(y_train),"size must be the same!"
x_mean = np.mean(x_train)
y_mean = np.mean(y_train)
num = (x_train - x_mean).dot(y_train - y_mean)
d = (x_train - x_mean).dot(x_train - x_mean)
self.a_ = num/d
self.b_ = y_mean - self.a_*x_mean
return self
只需要修改其中的fit函数即可,测试发现,进行向量化运算可以带来10倍以上的性能提升。
网友评论