凌云时刻 · 技术
导读:这篇笔记主要介绍线性回归算法,对在第一篇笔记中介绍过的线性回归算法进行实现。kNN算法主要解决的是分类问题,并且它的结果不具备良好的解释性。线性回归算法主要解决回归问题,它的结果具有良好的可解释性,和kNN算法的介绍过程一样,线性回归算法也蕴含了机器学习中很多重要的思想,并且它是许多强大的非线性模型的基础。
作者 | 计缘
来源 | 凌云时刻(微信号:linuxpk)
简单线性回归
在第一篇笔记中,我们举过房屋面积大小和价格例子,将其绘制在二维坐标图上,横轴表示房屋面积,纵轴表示房屋价格,这里样本特征数据只有一个,那就是房屋面积,而在kNN算法的分类问题中,二维坐标图上横纵轴表示的都是样本特征数据,这是一个比较明显的区别。如果线性回归问题要在图中表示两种样本特征数据的话就需要三维空间坐标来表示。我们一般将只有一种样本特征数据的线性回归问题称为简单线性回归问题。
线性回归其实就是寻找一条直线,最大程度的拟合样本特征和样本输出标记之间的关系。
我们来看上面这张图,大家知道直线的方程是 ,那么点 肯定是在一条直线上,该条直线方程为 ,那么点 的横轴值为 ,既是 的样本特征值,纵轴值为 ,既是 的样本输出值。我们假设图中的红线就是拟合直线,方程为 ,也就是将 代入这条红线,会得到一个预测的纵轴值 。我们希望真值 y(i)和预测值 的差值越小,说明我们的拟合直线拟合的越好。
因为差值有正有负,为了保证都是正数,所以将差值进行平方,之所以不用绝对值,是为了方便求导数。
方程求导的知识可参阅 《机器学习笔记一之机器学习定义、导数、最小二乘》 。
将所有样本特征都考虑到,既将所有真值和预测值的差值求和:
将 代入上面的公式就得到:
上面的公式我们称为损失函数(Loss Function),损失函数值越小,我们的拟合直线越好。在Loss函数中, 和 是变量,所以我们要做的就是找到使Loss函数值最小的 和 。这个套路是近乎所有参数学习算法常用的套路,既通过分析问题,确定问题的损失函数,通过最优化损失函数获得机器学习的模型。像线性回归、多项式回归、逻辑回归、SVM、神经网络等都是这个套路。
上述的Loss函数是一个典型的最小二乘法的问题,既通过最小化误差的平方和寻找数据的最佳函数匹配。求函数的最小值就会用到导数这个数学工具,具体如何推导上面的Loss函数可以参见第一篇学习笔记,这里不再累赘。最后得出 和 的求解公式为:
实现简单线性回归
我们先在Jupyter Notebook中实现:
import numpy as np
import matplotlib.pyplot as plt
# 先模拟一组简单的样本特征数据和样本输出数据
x = np.array([1., 2., 3., 4., 5.])
y = np.array([1., 3., 2., 3., 5.])
# 将这组数据绘制出来
plt.scatter(x, y)
plt.axis([0, 6, 0, 6])
plt.show()
然后我们使用上面推导出的公式求出 和 :
a = (np.mean(x)*np.mean(y) - np.mean(x*y))/(np.mean(x)**2 - np.mean(x**2))
a
# 结果
0.80000000000000071
b = np.mean(y) - a*np.mean(x)
b
# 结果
0.39999999999999769
# 利用a和b绘制出拟合直线
plt.scatter(x, y)
plt.plot(x, a*x+b, color="r")
plt.axis([0, 6, 0, 6])
plt.show()
# 新来一个特征值,利用拟合直线计算输出值
x_predict = 6
y_predict = a*x_predict + b
y_predict
# 结果
5.200000000000002
我们在PyCharm中封装我们自己的简单线性回归方法:
import numpy as np
class SimpleLinearRegression:
def __init__(self):
self.a_ = None
self.b_ = None
# 根据训练数据集x_train和y_train训练简单线性回归模型
def fit(self, x_train, y_train):
assert x_train.ndim == 1, \
"简单线性回归只能处理一个样本特征数据,所以x_train必须是一维向量"
assert len(x_train) == len(y_train), \
"x_train和y_train的数量必须要对应"
self.a_ = (np.mean(x_train) * np.mean(y_train) - np.mean(x_train * y_train)) / (np.mean(x_train) ** 2 - np.mean(x_train ** 2))
self.b_ = np.mean(y_train) - self.a_ * np.mean(x_train)
return self
# 给定待预测数据集x_predict,返回预测输出结果向量
def predict(self, x_predict):
assert x_predict.ndim == 1, "因为是简单线性回归,所以待预测数据集必须是一维向量"
assert self.a_ is not None and self.b_ is not None, "必须先执行fit方法计算a和b"
return np.array([self._predict(x) for x in x_predict])
# 给定单个待预测数据x_single,返回x_single的预测结果
def _predict(self, x_single):
return self.a_ * x_single + self.b_
def __repr__(self):
return "SimpleLinearRegression()"
然后我们就可以在Jupyter Notebook中使用我们封装的简单线性回归方法:
from myML.SimpleLinearRegression import SimpleLinearRegression
slr = SimpleLinearRegression()
slr.fit(x, y)
slr.predict(np.array([x_predict]))
# 结果
array([ 5.2])
slr.a_
# 结果
0.80000000000000071
slr.b_
# 结果
0.39999999999999769
END
往期精彩文章回顾
机器学习笔记(六):数据归一化
机器学习笔记(五):超参数
机器学习笔记(四):kNN算法
机器学习笔记(三):NumPy、Matplotlib、kNN算法机器学习笔记(二):矩阵、环境搭建、NumPy
机器学习笔记(一):机器的学习定义、导数和最小二乘
Kafka从上手到实践 - 实践真知:搭建Kafka相关的UI工具
Kafka从上手到实践 - Kafka集群:启动Kafka集群
Kafka从上手到实践 - Kafka集群:Kafka Listeners
Kafka从上手到实践 - Kafka集群:配置Broker
长按扫描二维码关注凌云时刻
每日收获前沿技术与科技洞见