线性回归 最小二乘法的求解推导与基于Python的底层代码实现

简介: 作为最常见的方法之一,线性回归仍可视为有监督机器学习的方法之一,同时也是一种广泛应用统计学和数据分析的基本技术。它是一种用于估计两个或多个变量之间线性关系的方法,其中一个变量是自变量,另一个变量是因变量。线性回归假设这两个变量之间存在线性关系,并试图找到一条最佳拟合直线,使预测值与实际值之间的误差最小化。

作为最常见的方法之一,线性回归仍可视为有监督机器学习的方法之一,同时也是一种广泛应用统计学和数据分析的基本技术。它是一种用于估计两个或多个变量之间线性关系的方法,其中一个变量是自变量,另一个变量是因变量。线性回归假设这两个变量之间存在线性关系,并试图找到一条最佳拟合直线,使预测值与实际值之间的误差最小化。



ac26054d89f8b85638eb227770baf29c.png




1 线性回归模型

1.1 模型本体

线性回归模型假设因变量 y yy 与自变量 x 1 , x 2 , . . . , x p   之间存在线性关系,即

image.png

其中,β 0 \beta_0β 0  是截距,β 1 , β 2 , . . . , β p \beta_1, \beta_2, ..., \beta_pβ 1 ,β,...,β p  是自变量的系数,ϵ \epsilonϵ 是误差项。线性回归模型的目标是估计系数 β 0 , β 1 , β 2 , . . . , β p \beta_0, \beta_1, \beta_2, ..., \beta_pβ 0 ,β 1 ,β 2,...,β p ,使得模型对因变量 y yy 的预测误差最小。


1.2 最小二乘法求解

最小二乘法是一种用于估计线性回归模型参数的常用方法,它的原理是寻找最小化残差平方和的系数估计值。残差是预测值与实际值之间的差异,残差平方和是所有残差平方的和。

image.png


最小化残差平方和的解可以用公式表示为

image.png

其中,β ^ \hat{\beta}  是系数估计值,X XX 是自变量矩阵,y yy 是因变量向量。如果 X T X X^TXX TX 可逆,则上述公式存在唯一解。


1.3 最小二乘求解推导

假设我们有一个大小为 m×n 的数据集,其中每个样本由 n 个特征和一个输出值组成。我们用 X 来表示数据集中的所有特征,用 Y 来表示数据集中的所有输出值。我们的目标是找到一个大小为 n×1 的权重向量 θ,使得 X*θ 和 Y 之间的误差最小化。


为了最小化误差,我们定义一个代价函数 J(θ),如下所示:

image.png

我们的目标是找到一个最小化代价函数的 θ 值。为了找到最小化代价函数的 θ 值,我们需要对代价函数求导数,令导数为 0,求得 θ。


我们首先对代价函数 J(θ) 进行展开:

image.png


我们对 θ 求导数,得到:(矩阵求导规则如有遗忘,请查看后面的表格)

image.png


令导数为 0,解得:

image.png

在第二部分的代码中,将直接使用我们推导的结果进行计算。


附:矩阵求导规则

3c92d0b527b0ebac436420baa2c3ec5b.png


2 最小二乘法求解代码

代码部分使用回归案例的经典数据集:波士顿房价数据集。其中x 1 x_{1}x 1

代表房屋面积,x 2 x_{2}x 2

代表房间数量,Y代表房价。


2.1 原始数据

X_ = np.array([  
    [10, 1],  
    [15, 1],  
    [20, 1],  
    [30, 1],  
    [50, 2],  
    [60, 1],  
    [60, 2],  
    [70, 2]]).reshape((-1, 2))  
Y = np.array([0.8, 1.0, 1.8, 2.0, 3.2, 3.0, 3.1, 3.5]).reshape((-1, 1))


此处reshape进行了兜底操作,实际上数据结构已经符合要求,对于此示例数据结构不加不会报错,但可以避免日后输入不规范带来的Bug。


2.2 判断是否有截距项并进行操作

flag = True
if flag:  
    # 添加一个截距项对应的X值  
    X = np.column_stack((X_, np.ones(shape=(X_.shape[0], 1))))  
else:  
    # 不加入截距项  
    X = X_


添加截距项的方法,本质上是给X在最右侧添加了一个新的特征,但该特征恒为1。对应该特征的自变量系数即为截距。


2.3 求解θ \thetaθ

X = np.mat(X)  
Y = np.mat(Y)
theta = (X.T * X).I * X.T * Y  
print(theta)


此处使用np.mat,可以将ndarray转为矩阵。转换之后矩阵的计算敲代码会更加容易,可以直接使用矩阵乘法和求逆矩阵等操作。如果不转换也可以,须将计算theta的部分改为:

theta = np.dot(np.dot(np.linalg.inv(np.dot(X.T, X)), X.T), Y)


层层嵌套,看起来就有些复杂了。


2.4 模型的使用

if flag:  
    x = np.mat(np.array([[55.0, 2.0,1.0]]))  
else:  
    x = np.mat(np.array([[55.0, 2.0]]))  
pred_y = x * theta

print(f"当面积为55平并且房间数目为2的时候,预测价格为:{float(pred_y):.2f}")


此处直接使用计算后的theta进行预测,并设置输出保留两位小数。


2.5 绘制结果

绘制的结果应该包含两部分,实际数据的散点图和方程所表示的平面。首先绘制散点图。


from mpl_toolkits.mplot3d import Axes3D
x1 = X[:, 0]  
x2 = X[:, 1]  
fig = plt.figure()  
ax = Axes3D(fig)  
ax.scatter(x1, x2, Y, s=40, c='r')

aaf494d8b3e700c9d416f2e6ab37c2b4.png


之后绘制方程所表示的平面,这里稍微麻烦一点。


x = np.arange(0, 100)  
y = np.arange(0, 4)  
x, y = np.meshgrid(x, y)


首先指定了x和y的范围,然后使用meshgrid计算由x和y范围内的点形成的网格的坐标。meshgrid前xydeshape分别为(100,)(4,),meshgrid后xy的顺序均为(4,100)。In other words,我们得到了这400个点对应的xy坐标。随后


如果希望使用矩阵与数值直接相乘,(4,100)无法和(1,1)相乘,需要把theat转换成浮点数,即

def predict(x1, x2, theta, base=False):
    if base:
        y_ = x1 * float(theta[0]) + x2 * float(theta[1]) + float(theta[2])
    else:
        y_ = x1 * theta[0] + x2 * theta[1]
    return y_
z = predict(x1, x2, theta, base=True)
z.shape = x1.shape
1


如果希望使用矩阵与矩阵相乘,将x1,x2组合成一个矩阵X,然后:

def predict(x1, x2, theta, base=False):  
    if base:  
        y_ = X * self.theta[0:2] + self.theta[2]
    else:  
        y_ = X * self.theta
    return y_  
z = predict(X, theta, base=True)
z.shape = x1.shape


两种方法获得z后,都要将z的shape同样转换为(4,100)。

ax.plot_surface(x1, x2, z, rstride=1, cstride=1, cmap=plt.cm.jet)  ##画超平面   cmap=plt.cm.jet彩图
ax.set_title(u'房屋租赁价格预测')
plt.show()


最后,使用plot_surface画图。rstride 和 cstride:分别表示行跨度和列跨度,用于控制曲面的网格线密度。默认值均为 1,表示每行和每列都画线。如果将其设置为 2,则表示每隔一行或一列画一条线。cmap:表示曲面的颜色映射,用于表示高度值与颜色的对应关系。可以使用 plt.cm 模块提供的内置颜色映射,如 plt.cm.jet 表示使用蓝-绿-黄-红的颜色映射。也可以自定义颜色映射。

最终的绘制结果为:



代码比较简单,就不发合并后的代码了,有任何问题直接文末留言即可。如需下载合并后的代码可点此下载30d7f34994f0c941adab7f854145f051.png

另外实际使用过程中建议封装成类。


在实际项目中,单纯的一次线性回归可能效果并不理想,此时可能会考虑才用特征扩张来优化模型,具体内容可查看

线性回归 特征扩展的原理与python代码的实现


相关文章
|
5月前
|
测试技术 Python
Python装饰器:为你的代码施展“魔法”
Python装饰器:为你的代码施展“魔法”
342 100
|
5月前
|
开发者 Python
Python列表推导式:优雅与效率的完美融合
Python列表推导式:优雅与效率的完美融合
370 104
|
5月前
|
Python
Python列表推导式:优雅与效率的艺术
Python列表推导式:优雅与效率的艺术
363 99
|
5月前
|
数据处理 Python
解锁Python列表推导式:优雅与效率的完美融合
解锁Python列表推导式:优雅与效率的完美融合
389 99
|
5月前
|
开发者 Python
Python列表推导式:一行代码的艺术与力量
Python列表推导式:一行代码的艺术与力量
514 95
|
6月前
|
Python
Python的简洁之道:5个让代码更优雅的技巧
Python的简洁之道:5个让代码更优雅的技巧
346 104
|
6月前
|
开发者 Python
Python神技:用列表推导式让你的代码更优雅
Python神技:用列表推导式让你的代码更优雅
606 99
|
5月前
|
缓存 Python
Python装饰器:为你的代码施展“魔法
Python装饰器:为你的代码施展“魔法
290 88
|
5月前
|
监控 机器人 编译器
如何将python代码打包成exe文件---PyInstaller打包之神
PyInstaller可将Python程序打包为独立可执行文件,无需用户安装Python环境。它自动分析代码依赖,整合解释器、库及资源,支持一键生成exe,方便分发。使用pip安装后,通过简单命令即可完成打包,适合各类项目部署。
1069 68
|
6月前
|
设计模式 人工智能 API
AI智能体开发实战:17种核心架构模式详解与Python代码实现
本文系统解析17种智能体架构设计模式,涵盖多智能体协作、思维树、反思优化与工具调用等核心范式,结合LangChain与LangGraph实现代码工作流,并通过真实案例验证效果,助力构建高效AI系统。
815 7

推荐镜像

更多