当前位置: 首页 > news >正文

python 数据拟合(线性拟合、多项式回归)

1.线性拟合

如图,有一组数据,似乎围绕着一条直线,上下浮动.

如何找到这条直线的表达式呢??

(数据来源的代码如下:

import numpy as np
import matplotlib.pyplot as plt# ============数据生成==================
# 生成特征数据 X:100个 [0,3) 区间的均匀分布随机数
X = 3 * np.random.rand(100)  # np.random.rand生成[0,1)均匀分布,乘以3扩展到[0,3)# 生成目标数据 y:线性关系 y = 4 + 3X + 高斯噪声
y = 4 + 3 * X + np.random.randn(100)  # np.random.randn生成标准正态分布噪声# 可视化原始数据
plt.plot(X, y, 'b.')  # 蓝色点图
plt.xlabel('x1')  # x轴标签
plt.ylabel('y')  # y轴标签
plt.axis([0, 3, 0, 20])  # 设置坐标范围:x[0,3], y[0,20]
plt.show()

通过np.random随机生成噪音,环绕在  y = 4 + 3x 周围

==========================

方法一:正规方程法(Normal Equation)

通过解析解直接计算线性回归的最优参数,无需迭代。其核心是最小化均方误差(MSE)损失函数,通过数学推导得到闭式解(Closed-form Solution)。

代码:

# ===========方法一:正规方程法(直接计算最优参数)=============
X_b = np.c_[np.ones((100, 1)), X]  # 添加偏置项列(全1列),将X转换为(100,2)矩阵
theta_best = np.linalg.inv(X_b.T.dot(X_b)).dot(X_b.T).dot(y)  # 正规方程公式:(X^T X)^-1 X^T y# 可视化正规方程法的拟合结果
plt.plot(X, y, 'b.')  # 原始数据
X_new = np.array([[0], [3]])  # 定义要预测的x范围(0到3)
X_new_b = np.c_[np.ones((2, 1)), X_new]  # 为预测点添加偏置项
y_predict = X_new_b.dot(theta_best)  # 计算预测值
plt.plot(X_new, y_predict, 'r-', linewidth=2, label='Normal Equation')  # 绘制红色拟合线
plt.xlabel('x1')
plt.ylabel('y')
plt.axis([0, 3, 0, 20])
plt.title('Normal Equation')
plt.legend()
plt.show()
print("正规方程法 - 截距:", theta_best[0].round(3), "斜率:", theta_best[1].round(3))

运行后,输出:

正规方程法 - 截距: 4.286 斜率: 2.797

得到表达式 :y = 4.286 +2.797x

===================

方法二:梯度下降法(Gradient Descent)

通过迭代更新参数,沿着损失函数的负梯度方向逐步逼近最小值。其核心是不断修正参数,使得损失函数J(θ)最小化。

代码:

# ===========方法二:梯度下降法(迭代优化参数)=============
m = 100  # 样本数量
theta = np.random.randn(2, 1)  # 随机初始化参数(2x1向量)
eta = 0.05  # 学习率(步长)
n_iterations = 2000  # 最大迭代次数
tolerance = 1e-4  # 收敛阈值(损失变化小于此值时停止)# 准备数据矩阵(与正规方程法相同)
X_b = np.c_[np.ones((100, 1)), X]  # 添加偏置项
X_new = np.array([[0], [3]])  # 预测点
X_new_b = np.c_[np.ones((2, 1)), X_new]  # 为预测点添加偏置项previous_loss = float('inf')  # 初始化前一次损失为无穷大
for iteration in range(n_iterations):# 计算梯度(MSE损失函数的导数)gradients = (1 / m) * X_b.T.dot(X_b.dot(theta) - y.reshape(-1, 1))  # 【修正梯度计算】# 更新参数new_theta = theta - eta * gradients# 计算当前损失(MSE)current_loss = np.mean((X_b.dot(theta) - y.reshape(-1, 1)) ** 2)# 提前停止条件:损失变化小于阈值if abs(previous_loss - current_loss) < tolerance:breaktheta = new_theta  # 更新参数previous_loss = current_loss  # 记录当前损失# 可视化梯度下降法的拟合结果
plt.plot(X, y, 'b.')  # 原始数据
y_predict = X_new_b.dot(theta)  # 计算预测值
plt.plot(X_new, y_predict, 'g--', linewidth=2, label='Gradient Descent')  # 绿色虚线
plt.xlabel('x1')
plt.ylabel('y')
plt.axis([0, 3, 0, 20])
plt.title(f'Gradient Descent (eta={eta}, iterations={iteration})')
plt.legend()
plt.show()print("梯度下降法 - 截距:", theta[0][0].round(3), "斜率:", theta[1][0].round(3))

运行后,输出:

梯度下降法 - 截距: 4.156 斜率: 2.869

得到表达式 y= 4.156 +2.869x

线性拟合,完整代码:

import numpy as np
import matplotlib.pyplot as plt# ============数据生成==================
# 生成特征数据 X:100个 [0,3) 区间的均匀分布随机数
X = 3 * np.random.rand(100)  # np.random.rand生成[0,1)均匀分布,乘以3扩展到[0,3)# 生成目标数据 y:线性关系 y = 4 + 3X + 高斯噪声
y = 4 + 3 * X + np.random.randn(100)  # np.random.randn生成标准正态分布噪声# 可视化原始数据
plt.plot(X, y, 'b.')  # 蓝色点图
plt.xlabel('x1')  # x轴标签
plt.ylabel('y')  # y轴标签
plt.axis([0, 3, 0, 20])  # 设置坐标范围:x[0,3], y[0,20]
plt.show()# =================拟合=============================# ===========方法一:正规方程法(直接计算最优参数)=============
X_b = np.c_[np.ones((100, 1)), X]  # 添加偏置项列(全1列),将X转换为(100,2)矩阵
theta_best = np.linalg.inv(X_b.T.dot(X_b)).dot(X_b.T).dot(y)  # 正规方程公式:(X^T X)^-1 X^T y# 可视化正规方程法的拟合结果
plt.plot(X, y, 'b.')  # 原始数据
X_new = np.array([[0], [3]])  # 定义要预测的x范围(0到3)
X_new_b = np.c_[np.ones((2, 1)), X_new]  # 为预测点添加偏置项
y_predict = X_new_b.dot(theta_best)  # 计算预测值
plt.plot(X_new, y_predict, 'r-', linewidth=2, label='Normal Equation')  # 绘制红色拟合线
plt.xlabel('x1')
plt.ylabel('y')
plt.axis([0, 3, 0, 20])
plt.title('Normal Equation')
plt.legend()
plt.show()
print("正规方程法 - 截距:", theta_best[0].round(3), "斜率:", theta_best[1].round(3))# ===========方法二:梯度下降法(迭代优化参数)=============
m = 100  # 样本数量
theta = np.random.randn(2, 1)  # 随机初始化参数(2x1向量)
eta = 0.05  # 学习率(步长)
n_iterations = 2000  # 最大迭代次数
tolerance = 1e-4  # 收敛阈值(损失变化小于此值时停止)# 准备数据矩阵(与正规方程法相同)
X_b = np.c_[np.ones((100, 1)), X]  # 添加偏置项
X_new = np.array([[0], [3]])  # 预测点
X_new_b = np.c_[np.ones((2, 1)), X_new]  # 为预测点添加偏置项previous_loss = float('inf')  # 初始化前一次损失为无穷大
for iteration in range(n_iterations):# 计算梯度(MSE损失函数的导数)gradients = (1 / m) * X_b.T.dot(X_b.dot(theta) - y.reshape(-1, 1))  # 【修正梯度计算】# 更新参数new_theta = theta - eta * gradients# 计算当前损失(MSE)current_loss = np.mean((X_b.dot(theta) - y.reshape(-1, 1)) ** 2)# 提前停止条件:损失变化小于阈值if abs(previous_loss - current_loss) < tolerance:breaktheta = new_theta  # 更新参数previous_loss = current_loss  # 记录当前损失# 可视化梯度下降法的拟合结果
plt.plot(X, y, 'b.')  # 原始数据
y_predict = X_new_b.dot(theta)  # 计算预测值
plt.plot(X_new, y_predict, 'g--', linewidth=2, label='Gradient Descent')  # 绿色虚线
plt.xlabel('x1')
plt.ylabel('y')
plt.axis([0, 3, 0, 20])
plt.title(f'Gradient Descent (eta={eta}, iterations={iteration})')
plt.legend()
plt.show()print("梯度下降法 - 截距:", theta[0][0].round(3), "斜率:", theta[1][0].round(3))

2.多项式回归

如图,有一组数据,近似一条曲线

如何找到拟合的曲线?

(数据来源:

#===========生成随机数据(x,y)=============
m=100#生成100个点
X=6*np.random.rand(m,1)-3        #(x范围为 -3 ,3)y=0.5*X**2+X+np.random.randn(m,1) # y = 0.5x²+x#画出随机数据
plt.plot(X,y,'b.')
plt.xlabel('x1')
plt.ylabel('y')
plt.axis([-3,3,-5,10])
plt.show()

多项式回归(Polynomial Regression):
通过将原始特征 X 转换为多项式特征,将非线性问题转化为线性问题,再使用线性回归模型拟合。

核心思想:用线性模型拟合非线性关系,通过增加高阶项扩展特征空间。

代码:

import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression#===========生成随机数据(x,y)=============
m=100#生成100个点
X=6*np.random.rand(m,1)-3        #(x范围为 -3 ,3)y=0.5*X**2+X+np.random.randn(m,1) # y = 0.5x²+x#画出随机数据
plt.plot(X,y,'b.')
plt.xlabel('x1')
plt.ylabel('y')
plt.axis([-3,3,-5,10])
plt.show()#===============拟合========================
#PolynomialFeatures类用于将输入数据转换为多项式特征,其中degree参数指定了多项式的阶数(即最高次项),include_bias参数指定是否包括截距项(即常数项)。
poly_features = PolynomialFeatures(degree=2,include_bias=False)
#将转换后的特征矩阵存储在X_poly变量中
X_poly = poly_features.fit_transform(X)#线性回归模型对象lin_reg
lin_reg = LinearRegression()
#使用X_poly和y拟合了模型
lin_reg.fit(X_poly,y)
#首先生成100个在-3到3之间均匀分布的数字
# 然后将这些数字reshape为一个100x1的矩阵
X_new = np.linspace(-3,3,100).reshape(100,1)
#使用之前训练好的多项式特征转换器poly_features对X_new进行特征转换
X_new_poly = poly_features.transform(X_new)
#使用线性回归模型lin_reg对X_new_poly进行预测,得到预测结果y_new。
y_new = lin_reg.predict(X_new_poly)
plt.plot(X,y,'b.')
plt.plot(X_new,y_new,'r--',label='prediction')
plt.axis([-3,3,-5,10])
plt.legend()
plt.show()print("y = "+str(lin_reg.intercept_[0].round(3))+" + "+str(lin_reg.coef_[0][0].round(3))+"x"+" + "+str(lin_reg.coef_[0][1].round(3))+"x²")

运行后输出:
y = 0.027 + 1.051x + 0.509x²

============

更换数据,

非常常见的y = e的x次方

修改代码,多项式扩展到4次方

poly_features = PolynomialFeatures(degree=4,include_bias=False)
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression#===========生成随机数据(x,y)=============
m=100#生成100个点X = 4*np.random.rand(m,1)y = 2.718**X#画出随机数据
plt.plot(X,y,'b.')
plt.xlabel('x1')
plt.ylabel('y')
plt.axis([0,5,0,80])
plt.show()#===============拟合========================
#PolynomialFeatures类用于将输入数据转换为多项式特征,其中degree参数指定了多项式的阶数(即最高次项),include_bias参数指定是否包括截距项(即常数项)。
poly_features = PolynomialFeatures(degree=4,include_bias=False)
#将转换后的特征矩阵存储在X_poly变量中
X_poly = poly_features.fit_transform(X)#线性回归模型对象lin_reg
lin_reg = LinearRegression()
#使用X_poly和y拟合了模型
lin_reg.fit(X_poly,y)
#首先生成100个在-3到3之间均匀分布的数字
# 然后将这些数字reshape为一个100x1的矩阵
X_new = np.linspace(0,5,100).reshape(100,1)
#使用之前训练好的多项式特征转换器poly_features对X_new进行特征转换
X_new_poly = poly_features.transform(X_new)
#使用线性回归模型lin_reg对X_new_poly进行预测,得到预测结果y_new。
y_new = lin_reg.predict(X_new_poly)
plt.plot(X,y,'b.')
plt.plot(X_new,y_new,'r--',label='prediction')
plt.axis([0,5,0,80])
plt.legend()
plt.show()print("y = "+str(lin_reg.intercept_[0].round(3))+" + "+str(lin_reg.coef_[0][0].round(3))+"x"+" + "+str(lin_reg.coef_[0][1].round(3))+"x**2"+" + "+str(lin_reg.coef_[0][2].round(3))+"x**3"+" + "+str(lin_reg.coef_[0][3].round(3))+"x**4")

运行后:

表达式:

y = 1.206 + -0.583x + 3.124x**2 + -1.366x**3 + 0.362x**4

提问:为什么和e的x次方的泰勒展开 不太一样呢?

http://www.lryc.cn/news/624250.html

相关文章:

  • Android Coil3视频封面抽取封面帧存Disk缓存,Kotlin(2)
  • 云计算:企业数字化转型的核心引擎
  • Kubernetes(K8s)常用命令全解析:从基础到进阶
  • 【Kubernetes】在 K8s 上部署 Prometheus
  • C语言基础:变量与进制详解
  • K8s的命名空间需要创建吗
  • 工具集成强化学习:AI数学推理能力的新跃迁
  • Java基础(九):Object核心类深度剖析
  • 图神经网络分享系列-node2vec(二)
  • 基于51单片机WIFI心率计脉搏体温测量仪APP设计
  • HTML应用指南:利用POST请求获取全国华为旗舰店门店位置信息
  • 《若依》权限控制
  • 上下文切换及线程操作相关内容
  • 学习雪花算法
  • linux-高级IO(中)
  • 【BFS 动态规划】P12382 [蓝桥杯 2023 省 Python B] 树上选点|普及+
  • Redis面试精讲 Day 25:Redis实现分布式Session与购物车
  • 【前端】使用Vue3过程中遇到加载无效设置点击方法提示不存在的情况,原来是少加了一个属性
  • [激光原理与应用-296]:理论 - 非线性光学 - 线性光学与非线性光学对比
  • (第十九期)用 VS Code 管理项目:目录文件夹与根目录,一次讲清
  • Vulkan笔记(五)-逻辑层与队列
  • halcon基于透视的可变形模型匹配
  • C预备知识01:
  • 数字电视:技术演进与未来展望
  • 用户认证技术
  • MySQL 函数大赏:聚合、日期、字符串等函数剖析
  • 静配中心配药智能化:基于高并发架构的Go语言实现
  • CPP异常
  • 新手向:Java方向讲解
  • 数据挖掘 3.5 支持向量机——边界和正则化