Python小白的数学建模课-23.数据拟合全集


  • 拟合是用一个连续函数(曲线)靠近给定的离散数据,使其与给定的数据相吻合。
  • 数据拟合的算法相对比较简单,但调用不同工具和方法时的函数定义和参数设置有所差异,往往使小白感到困惑。
  • 本文基于 Scipy 工具包,对单变量、多变量线性最小二乘拟合,指数函数、多项式函数、样条函数的非线性拟合,单变量、多变量的自定义函数拟合问题进行分析、给出完整例程和结果,数据拟合从此无忧。
  • 『Python小白的数学建模课 @ Youcans』带你从数模小白成为国赛达人。


文章目录

    • 1. 数据拟合
      • 1.1 数据拟合问题的分类
      • 1.2 数据拟合的原理和方法
      • 1.3 Python 数据拟合方法
    • 2. 线性最小二乘拟合
      • 2.1 线性最小二乘拟合函数说明
        • 2.1.1 scipy.optimize.leastsq 函数说明
        • 2.1.2 scipy.stats.linregress 函数说明
      • 2.2 Python 例程:单变量线性拟合
      • 2.3 Python 例程:多变量线性拟合
    • 3. 非线性函数数据拟合
      • 3.1 非线性拟合函数说明
      • 3.2 Python 例程:指数函数拟合
      • 3.3 Python 例程:多项式函数拟合
      • 3.4 Python 例程:样条曲线拟合
    • 4. 自定义函数曲线拟合
      • 4.1 scipy.optimize.curve_fit() 函数说明
      • 4.2 Python 例程:单变量自定义函数曲线拟合
      • 4.3 Python 例程:多变量自定义函数曲线拟合

1. 数据拟合

在科学研究和工程应用中经常通过测量、采样、实验等方法获得各种数据。对一组已知数据点集,通过调整拟合函数(曲线)的参数,使该函数与已知数据点集相吻合,这个过程称为数据拟合,又称曲线拟合。

插值和拟合都是根据一组已知数据点,求变化规律和特征相似的近似曲线的过程。但是插值要求近似曲线完全经过所有的给定数据点,而拟合只要求近似曲线在整体上尽可能接近数据点,并反映数据的变化规律和发展趋势。因此插值可以看作是一种特殊的拟合,是要求误差函数为 0 的拟合。

1.1 数据拟合问题的分类

数据拟合问题,可以从不同角度进行分类:

  • 按照拟合函数分类,分为线性函数和非线性函数。非线性函数用于数据拟合,常用的有多项式函数、样条函数、指数函数和幂函数,针对具体问题还有自定义的特殊函数显示。
  • 按照变量个数分类,分为单变量函数和多变量函数。
  • 按照拟合模型分类,分为基于模型的数据拟合和无模型的函数拟合。基于模型的数据拟合,是通过建立数学模型描述输入输出变量之间的关系,拟合曲线不仅能拟合观测数据,拟合模型的参数通常具有明确的物理意义。而无模型的函数拟合,是指难以建立描述变量关系的数学模型,只能采用通用的函数和曲线拟合观测数据,例如多项式函数拟合、样条函数拟合,也包括机器学习和神经网络模型,这种模型的参数通常没有明确的意义。

1.2 数据拟合的原理和方法

数据拟合通过调整拟合函数中的待定参数,从整体上接近已知的数据点集。

这是一个优化问题,决策变量是拟合函数的待定参数,优化目标是观测数据与拟合函数的函数值之间的某种误差指标。典型的优化目标是拟合函数值与观测值的误差平方和;当观测数据的重要性不同或分布不均匀时,也可以使用加权误差平方和作为优化目标。

数据拟合的基本方法是最小二乘法。对于观测数据 (xi,yi),i=1,..n(x_i,y_i),i=1,..n(xi,yi),i=1,..n,将观测值 yiy_iyi 与拟合函数 y=f(x,p)y=f(x,p)y=f(x,p)的计算值 f(xi)f(x_i)f(xi)的误差平方和最小作为优化问题的目标函数:
minJ(p1,⋯pm)=∑i=1n[yi−f(xi)]2min \; J(p_1, \cdots p_m) = \sum_{i=1}^n [y_i - f(x_i)]^2 minJ(p1,pm)=i=1n[yif(xi)]2
(p1,⋯pm)(p_1, \cdots p_m)(p1,pm) 是拟合函数中的待定参数。

对于线性拟合问题,设拟合函数为直线 f(x)=p0+p1∗xf(x) = p_0+p_1*xf(x)=p0+p1x, 由极值的必要条件 $ \partial J/\partial p_j = 0,; (j=0,1)$ 可以解出系数 p0,p1p_0, p_1p0,p1
p1=n∑i=1nxiyi−∑i=1nxi∑i=1nyin∑i=1nxi2−(∑i=1nxi)2p0=∑i=1nyin−a1∑i=1nxinp_1 = \frac{n \sum_{i=1}^n x_i y_i - \sum_{i=1}^n x_i \sum_{i=1}^n y_i} {n \sum_{i=1}^n x_i^2 - (\sum_{i=1}^n x_i)^2}\\ p_0 =\frac{\sum_{i=1}^n y_i}{n} - a_1 \frac {\sum_{i=1}^n x_i}{n} p1=ni=1nxi2(i=1nxi)2ni=1nxiyii=1nxii=1nyip0=ni=1nyia1ni=1nxi
对于多变量线性最小二乘问题,设拟合函数为直线 f(x)=p0+p1∗x1+⋯+pm∗xmf(x) = p_0+p_1*x_1+ \cdots +p_m*x_mf(x)=p0+p1x1++pmxm, 类似地,可以解出系数 p0,p1,⋯pmp_0, p_1, \cdots p_mp0,p1,pm

对于非线性函数的拟合问题,通常也是按照最小二乘法的思路,求解上述误差平方和最小化这个非线性优化问题,常用的具体算法有搜索算法和迭代算法两类。


1.3 Python 数据拟合方法

数据拟合是常用算法,Python 语言的很多工具包都提供了数据拟合方法,常用的如 Scipy、Numpy、Statsmodel、Scikit-learn 工具包都带有数据拟合的函数与应用。

Scipy 是最常用的 Python 工具包,本系列中非线性规划、插值方法也都是使用 Scipy 工具包实现,因此仍以 Scipy 工具包讲解数据拟合问题。

Scipy 工具包对于不同类型的数据拟合问题,提供了不同的函数或类。由于 Scipy 工具包是多个团队合作完成,而且经过了不断更新,因此调用不同函数和方法时的函数定义和参数设置有所差异,往往使小白感到困惑。

本文对单变量、多变量线性最小二乘拟合,指数函数、多项式函数、样条函数的非线性拟合,单变量、多变量的自定义函数拟合问题进行分析、给出完整例程和结果,数据拟合从此无忧。



2. 线性最小二乘拟合

2.1 线性最小二乘拟合函数说明

线性最小二乘拟合是最简单和最常用的拟合方法。scipy.optimize 工具箱中的 leastsq()、lsq_linear(),scipy.stats 工具箱中的 linregress(),都可以实现线性最小二乘拟合。

2.1.1 scipy.optimize.leastsq 函数说明

leastsq() 根据观测数据进行最小二乘拟合计算,只需要观测值与拟合函数值的误差函数和待定参数 的初值,返回拟合函数中的待定参数 (p1,⋯pm)(p_1, \cdots p_m)(p1,pm),但不能提供参数估计的统计信息。leastsq() 可以进行单变量或多变量线性最小二乘拟合,对变量进行预处理后也可以进行多项式函数拟合。

scipy.optimize.leastsq(func, x0, args=(), Dfun=None, full_output=0, col_deriv=0, ftol=1.49012e-08, xtol=1.49012e-08, gtol=0.0, maxfev=0, epsfcn=None, factor=100, diag=None)

主要参数:

  • func:可调用的函数,描述拟合函数的函数值与观测值的误差,形式为 error(p,x,y),具有一个或多个待定参数 p。误差函数的参数必须按照 (p,x,y) 的顺序排列,不能改变。
  • x0:一维数组,待定参数 (p1,⋯pm)(p_1, \cdots p_m)(p1,pm) 的初值。
  • args:元组,线性拟合时提供观测数据值 (xdata, ydata),观测数据 xdata 可以是一维数组(单变量问题),也可以是多维数组(多变量问题)。

返回值:

  • x:一维数组,待定参数 (p1,⋯pm)(p_1, \cdots p_m)(p1,pm) 的最小二乘估计值。

2.1.2 scipy.stats.linregress 函数说明

linregress() 根据两组观测数据 (x,y) 进行线性最小二乘回归,不仅返回拟合函数中的待定参数 (p1,p1)(p_1, p_1)(p1,p1),而且可以提供参数估计的各种统计信息,但只能进行单变量线性拟合。

scipy.stats.linregress(x, y=None, alternative=‘two-sided’)

主要参数:

  • x, y:x, y 是长度相同的一维数组。或者 x 是二维数组,且 y=none,则二维数组 x 相当于 长度相同的一维数组 x, y。

返回值:

  • slope:斜率,直线 f(x)=p0+p1∗xf(x) = p_0+p_1*xf(x)=p0+p1x 中的 p1p_1p1
  • intercept:截距,直线 f(x)=p0+p1∗xf(x) = p_0+p_1*xf(x)=p0+p1x 中的 p0p_0p0
  • rvalue:r^2 值,统计量。
  • pvalue:p 值,P检验的统计量。
  • stderr:标准差,统计量。

2.2 Python 例程:单变量线性拟合

程序说明:

  1. scipy.optimize.leastsq() 与 scipy.stats.linregress() 都可以进行单变量线性拟合。leastsq() 既可以用于单变量也可以用于多变量问题;linregress() 只能用于单变量问题,但可以给出很多参数估计的统计结果。
  2. leastsq() 要以子函数来定义观测值与拟合函数值的误差函数,例程中分别定义了拟合函数 fitfunc1(p, x) 与误差函数error1(p, x, y) ,是为了方便调用拟合函数计算拟合曲线在数据点的函数值。注意 p 为数组 。
  3. leastsq() 中误差函数的函数名可以任意定义,但误差函数的参数必须按照 (p,x,y) 的顺序排列,不能改变次序。
  4. leastsq() 中观测数据 (x, yObs) 是以动态参数 args 的方式进行传递的。这种处理方式非常独特,没有为什么, leastsq() 就是这样定义的。
  5. linregress() 只要将观测数据 (x,yObs) 作为参数,默认单变量线性拟合,不需要定义子函数。
  6. leastsq() 与 linregress() 进行线性拟合,得到的参数估计结果是相同的。

Python 例程:

# mathmodel25_v1.py
# Demo25 of mathematical modeling algorithm
# Demo of curve fitting with Scipy
# Copyright 2021 YouCans, XUPT
# Crated:2021-08-03# 1. 单变量线性拟合:最小二乘法 scipy.optimize.leastsq
import numpy as np
import matplotlib.pyplot as plt  # 导入 Matplotlib 工具包
from scipy.optimize import leastsq  # 导入 scipy 中的最小二乘法拟合工具
from scipy.stats import linregress  # 导入 scipy 中的线性回归工具def fitfunc1(p, x):  # 定义拟合函数为直线p0, p1 = p  # 拟合函数的参数y = p0 + p1*x  # 拟合函数的表达式return ydef error1(p, x, y):  # 定义观测值与拟合函数值的误差函数err = fitfunc1(p,x) - y  # 误差return err# 创建给定数据点集 (x,yObs)
p = [2.5, 1.5]  # y = p[0] + p[1] * x
x = np.array([0., 0.5, 1.5, 2.5, 4.5, 5.5, 7.5, 8.0, 8.5, 9.0, 10.0])
y = p[0] + p[1] * x  # 理论值 y
np.random.seed(1)
yObs = y + np.random.randn(x.shape[-1])  # 生成带有噪声的观测数据
# print(x.shape, y.shape, yObs.shape)# 由给定数据点集 (x,y) 求拟合函数的参数 pFit
p0 = [1, 1]  # 设置拟合函数的参数初值
pFit, info = leastsq(error1, p0, args=(x,yObs))  # 最小二乘法求拟合参数
print("Data fitting with Scipy.optimize.leastsq")
print("y = p[0] + p[1] * x")
print("p[0] = {:.4f}\np[1] = {:.4f}".format(pFit[0], pFit[1]))# 由拟合函数 fitfunc 计算拟合曲线在数据点的函数值
yFit = fitfunc1(pFit,x)# 比较:线性回归,可以返回斜率,截距,r 值,p 值,标准误差
slope, intercept, r_value, p_value, std = linregress(x, yObs)
print("\nLinear regress with Scipy.stats.linregress")
print("y = p[0] + p[1] * x")
print("p[0] = {:.4f}".format(intercept))  # 输出截距 intercept
print("p[1] = {:.4f}".format(slope))  # 输出斜率 slope
print("r^2_value: {:.4f}".format(r_value**2))  # 输出 r^2 值
print("p_value: {:.4f}".format(p_value))  # 输出 p 值
print("std: {:.4f}".format(std))  # 输出标准差 std# 绘图
fig, ax = plt.subplots(figsize=(8,6))
ax.text(8,3,"youcans-xupt",color='gainsboro')
ax.set_title("Data fitting with linear least squares")
plt.scatter(x, yObs, label="observed data")
plt.plot(x, y, 'r--', label="theoretical curve")
plt.plot(x, yFit, 'b-', label="fitting curve")
plt.legend(loc="best")
plt.show()

程序运行结果:

Data fitting with Scipy.optimize.leastsq
y = p[0] + p[1] * x
p[0] = 2.2688
p[1] = 1.5528Linear regress with Scipy.stats.linregress
y = p[0] + p[1] * x
p[0] = 2.2688
p[1] = 1.5528
r^2_value: 0.9521
p_value: 0.0000
std: 0.1161

在这里插入图片描述

2.3 Python 例程:多变量线性拟合

程序说明:

  1. scipy.optimize.leastsq() 既可以用于单变量也可以用于多变量问题,本例程求解一个二元线性拟合问题:y = p[0] + p[1] * x1 + p[2] * x2。
  2. leastsq() 求解多变量问题的方法与单变量问题类似,以子函数 error2(p, x1, x2, y) 来定义观测值与拟合函数值的误差函数,以动态参数 args 的方式传递观测数据 (x, yObs) 。
  3. leastsq() 中误差函数的函数名可以任意定义,但误差函数的参数必须按照 (p,x1,x2,y) 的顺序排列,不能改变次序。
  4. scipy 只能做一元线性回归,例程中通过调用 statsmodels.api 进行多元线性回归,可以得到各种统计参数,供读者参考。

Python 例程:

# mathmodel25_v1.py
# Demo25 of mathematical modeling algorithm
# Demo of curve fitting with Scipy
# Copyright 2021 YouCans, XUPT
# Crated:2021-08-03# 2. 多变量线性拟合:最小二乘法 scipy.optimize.leastsq
import numpy as np
import matplotlib.pyplot as plt  # 导入 Matplotlib 工具包
from scipy.optimize import leastsq  # 导入 scipy 中的最小二乘法工具def fitfunc2(p, x1, x2):  # 定义拟合函数为直线p0, p1, p2 = p  # 拟合函数的参数y = p0 + p1*x1 + p2*x2  # 拟合函数的表达式return ydef error2(p, x1, x2, y):  # 定义观测值与拟合函数值的误差函数err = fitfunc2(p, x1, x2) - y  # 计算残差return err# 创建给定数据点集 (x,yObs)
np.random.seed(1)
p = [2.5, 1.5, -0.5]  # y = p[0] + p[1] * x1 + p[2] * x2
x1 = np.array([0., 0.5, 1.5, 2.5, 4.5, 5.5, 7.5, 8.0, 8.5, 9.0, 10.0])
x2 = np.array([0., 1.0, 1.5, 2.2, 4.8, 5.0, 6.3, 6.8, 7.1, 7.5, 8.0])
z = p[0] + p[1]*x1 + p[2]*x2  # 理论值 z
zObs = z + np.random.randn(x1.shape[-1])  # 生成带有噪声的观测数据
print(x1.shape, z.shape, zObs.shape)# 由给定数据点集 (x,z) 求拟合函数的参数 pFit
p0 = [1, 1, 1]  # 设置拟合函数的参数初值
pFit, info = leastsq(error2, p0, args=(x1,x2,zObs))  # 最小二乘法求拟合参数
print("Data fitting with Scipy.optimize.leastsq:")
print("z = p[0] + p[1]*x1 + p[1]*x2")
print("p[0]={:.4f}\np[1]={:.4f}\np[2]={:.4f}".format(pFit[0], pFit[1], pFit[2]))# 由拟合函数 fitfunc 计算拟合曲线在数据点的函数值
zFit = fitfunc2(pFit, x1, x2)# 多元线性回归:最小二乘法(OLS)
import statsmodels.api as sm
x0 = np.ones(x1.shape[-1])  # 截距列 x0=[1,...1]
X = np.column_stack((x0, x1, x2))  # (nSample,3): [x0, x1, x2]
model = sm.OLS(zObs, X)  # 建立 OLS 模型: y = b0*x0 + b1*x1 + b2*x2 + e
results = model.fit()  # 返回模型拟合结果
zFit = results.fittedvalues  # 模型拟合的 y值
print(results.summary())  # 输出回归分析的摘要
print("\nOLS model: y = b0*x0 + b1*x1 + b2*x2")
print('Parameters: ', results.params)  # 输出:拟合模型的系数

程序运行结果:

Data fitting with Scipy.optimize.leastsq
z = p[0] + p[1]*x1 + p[1]*x2
p[0]=2.6463
p[1]=2.2410
p[2]=-1.3710OLS Regression Results 
OLS model: y = b0*x0 + b1*x1 + b2*x2
Parameters:  [ 2.64628055  2.24100973 -1.37104475]
==============================================================================coef    std err          t      P>|t|      [0.025      0.975]
------------------------------------------------------------------------------
const          2.6463      0.942      2.808      0.023       0.473       4.820
x1             2.2410      1.043      2.148      0.064      -0.165       4.647
x2            -1.3710      1.312     -1.045      0.326      -4.396       1.654
==============================================================================


3. 非线性函数数据拟合

3.1 非线性拟合函数说明

非线性函数是非常广泛的概念。本节讨论指数函数、多项式函数和样条函数三种常用的通用形式的非线性函数拟合问题,分别使用了 Scipy 工具包中的 scipy.optimize.leastsq()、scipy.linalg.lstsq() 和 scipy.interpolate.UnivariateSpline() 函数。

scipy.optimize.leastsq() 的使用方法已在本文 2.1 中进行了介绍,scipy.interpolate.UnivariateSpline() 的使用方法在《22. 插值方法》文中进行了介绍,以下介绍 scipy.linalg.lstsq() 函数。

lstsq() 函数只要传入观测数据 (x,yObs),并将 x 按多项式阶数转换为 X,即可求出多项式函数的系数,不需要定义拟合函数或误差函数,非常适合比较不同阶数的多项式函数拟合的效果。

scipy.linalg.lstsq(a, b, cond=None, overwrite_a=False, overwrite_b=False, check_finite=True, lapack_driver=None)

主要参数:

  • a:(m,n) 数组,表示方程 Ax=b 的左侧。
  • b:(m,) 数组,表示方程 Ax=b 的右侧。

返回值:

  • x:最小二乘的解,指多项式函数的系数。

注意:lstsq() 函数中求解方程 Ax=b,A 是指由观测数据 xix_ixi 按多项式阶数转换为矩阵 (xi0,xi1,...xim),i=1,n(x_i^0,x_i^1,...x_i^m),i=1,n(xi0,xi1,...xim),i=1,n,b 是指 yi,i=1,ny_i,i=1,nyi,i=1,n,而 x 是指多项式函数的系数,详见例程。


3.2 Python 例程:指数函数拟合

程序说明:

  1. scipy.optimize.leastsq() 本质上是求解带有待定参数的误差函数最小化问题,因此可以用于指数函数的最小二乘拟合。类似地,原理上 leastsq() 也可以用于其它形式非线性函数的拟合问题,但对于某些函数拟合误差可能会比较大。
  2. leastsq() 以子函数 error3(p, x, y) 来定义观测值与拟合函数值的误差函数,以动态参数 args 的方式传递观测数据 (x, yObs) 。
  3. leastsq() 中误差函数的函数名可以任意定义,但误差函数的参数必须按照 (p,x1,x2,y) 的顺序排列,不能改变次序。

Python 例程:

# mathmodel25_v1.py
# Demo25 of mathematical modeling algorithm
# Demo of curve fitting with Scipy
# Copyright 2021 YouCans, XUPT
# Crated:2021-08-03# 3. 非线性函数拟合:指数函数拟合(exponential function)
import numpy as np
import matplotlib.pyplot as plt  # 导入 Matplotlib 工具包
from scipy.optimize import leastsq  # 导入 scipy 中的最小二乘法工具def fitfunc3(p, x):  # 定义拟合函数p0, p1, p2 = p  # 拟合函数的参数y = p0 + p1 * np.exp(-p2*x)  # 拟合函数的表达式return ydef error3(p, x, y):  # 定义残差函数err = fitfunc3(p,x) - y  # 残差return err# 创建给定数据点集 (x,yObs)
p = [0.5, 2.5, 1.5]  # y = p0 + p1 * np.exp(-p2*x)
x = np.linspace(0, 5, 50)
y = fitfunc3(p, x)
np.random.seed(1)
yObs = y + 0.2*np.random.randn(x.shape[-1])  # 生成带有噪声的观测数据
# print(x.shape, y.shape, yObs.shape)# 由给定数据点集 (x,y) 求拟合函数的参数 pFit
p0 = [1, 1, 1]  # 设置拟合函数的参数初值
pFit, info = leastsq(error3, p0, args=(x,yObs))  # 最小二乘法求拟合参数
print("Data fitting of exponential function")
print("y = p0 + p1 * np.exp(-p2*x)")
print("p[0] = {:.4f}\np[1] = {:.4f}\np[2] = {:.4f}".format(pFit[0], pFit[1], pFit[2]))# 由拟合函数 fitfunc 计算拟合曲线在数据点的函数值
yFit = fitfunc3(pFit, x)# 绘图
fig, ax = plt.subplots(figsize=(8,6))
ax.set_title("Data fitting of exponential function")
plt.scatter(x, yObs, label="observed data")
plt.plot(x, y, 'r--', label="theoretical curve")
plt.plot(x, yFit, 'b-', label="fitting curve")
plt.legend(loc="best")
plt.show()

程序运行结果:

Data fitting of exponential function
y = p0 + p1 * np.exp(-p2*x)
p[0] = 0.5216
p[1] = 2.5742
p[2] = 1.6875

在这里插入图片描述


3.3 Python 例程:多项式函数拟合

程序说明:

  1. scipy.optimize.leastsq() 本质上是求解带有待定参数的误差函数最小化问题,因此可以用于多项式函数的最小二乘拟合,使用方法与线性拟合、指数拟合类似。
  2. 由于 leastsq() 要以子函数 error(p, x, y) 来定义观测值与拟合函数值的误差函数,在比较不同阶数的多项式函数拟合时需要定义多个对应的误差函数,比较繁琐。
  3. scipy.linalg.lstsq() 只要传入观测数据 (x,yObs),并将 x 按多项式阶数转换为 X,即可求出多项式函数的系数,不需要定义拟合函数或误差函数,非常适合比较不同阶数的多项式函数拟合的效果。
  4. 对于相同阶数的多项式函数,leastsq() 与 lstsq() 的参数估计和拟合结果是相同的。
  5. 增大多项式的阶数,可以减小拟合曲线与观测数据的误差平方和,但也更容易导致过拟合,虽然能更好地拟合训练数据,但并不能真实反映数据的总体规律,因而对于训练数据以外的测试数据的拟合效果反而降低了。

Python 例程:

# mathmodel25_v1.py
# Demo25 of mathematical modeling algorithm
# Demo of curve fitting with Scipy
# Copyright 2021 YouCans, XUPT
# Crated:2021-08-03# 4. 非线性函数拟合:多项式函数拟合(Polynomial function)
import numpy as np
import matplotlib.pyplot as plt  # 导入 Matplotlib 工具包
from scipy.linalg import lstsq  # 导入 scipy 中的 linalg, stats 函数库
from scipy.optimize import leastsq  # 导入 scipy 中的最小二乘法工具def fitfunc4(p, x):  # 定义拟合函数p0, p1, p2, p3 = p  # 拟合函数的参数y = p0 + p1*x + p2*x*x + p3*x*x*x  # 拟合函数的表达式return ydef error4(p, x, y):  # 定义观测值与拟合函数值的误差函数err = fitfunc4(p,x) - y  # 残差return err# 创建给定数据点集 (x,yObs)
p = [1.0, 1.2, 0.5, 0.8]  # y = p0 + ((x*x-p1)**2+p2) * np.sin(x*p3)
func = lambda x: p[0]+((x*x-p[1])**2+p[2])*np.sin(x*p[3])  # 定义 y=f(x)
x = np.linspace(-1, 2, 30)
y = func(x)  # 计算已知数据点的理论值 y =f(x)
np.random.seed(1)
yObs = y + 0.5*np.random.randn(x.shape[-1])  # 生成带有噪声的观测数据 yObs# 绘图
fig, ax = plt.subplots(figsize=(8,6))
ax.set_title("Polynomial fitting with least squares")
plt.scatter(x, yObs, label="observed data")
plt.plot(x, y, 'c--', label="theoretical curve")# 用 scipy.optimize.leastsq() 进行多项式函数拟合
p0 = [1, 1, 1, 1]  # 设置拟合函数的参数初值
pFit, info = leastsq(error4, p0, args=(x,yObs))  # 最小二乘法求拟合参数
yFit = fitfunc4(pFit, x)  # 由拟合函数 fitfunc 计算拟合曲线在数据点的函数值
ax.plot(x, yFit, '-', label='leastsq')
print("Polynomial fitting by scipy.optimize.leastsq")
print("y = p[0] + p[1]*x + p[2]*x^2 +p[3]*x^3")  # 拟合函数的表达式
print("p[0] = {:.4f}\np[1] = {:.4f}\np[2] = {:.4f}\np[3] = {:.4f}".format(pFit[0], pFit[1], pFit[2], pFit[3]))# 用 scipy.linalg.lstsq() 进行多项式函数拟合
print("\nPolynomial fitting by scipy.linalg.lstsq")
print("y = w[0] + w[1]*x + w[2]*x^2 + ... + w[m]*x^m")  # 拟合函数的表达式
# 最小二乘法多项式数据拟合,求解多项式函数的系数 W=[w[0],...w[m]]
for order in range(1,5):# order = 3  # 多项式阶数, mX = np.array([[(xi ** i) for i in range(order + 1)] for xi in x])Y = np.array(yObs).reshape((-1, 1))W, res, rnk, s = lstsq(X, Y)  # 最小二乘法求解 A*W = bprint("order={:d}".format(order))for i in range(order+1):  # W = [w[0],...w[order]]print("\tw[{:d}] = {:.4f}".format(i, W[i,0]))# 由拟合函数 fitfunc 计算拟合曲线在数据点的函数值yFit = X.dot(W)  # y = w[0] + w[1]*x + w[2]*x^2 + ... + w[m]*x^m# 绘图:n 次多项式函数拟合曲线ax.plot(x, yFit, '-', label='order={}'.format(order))plt.legend(loc="best")
plt.show()

程序运行结果:

Polynomial fitting by scipy.optimize.leastsq
y = p[0] + p[1]*x + p[2]*x^2 +p[3]*x^3
p[0] = 0.9586
p[1] = -0.4745
p[2] = -0.3581
p[3] = 1.1721Polynomial fitting by scipy.linalg.lstsq
y = w[0] + w[1]*x + w[2]*x^2 + ... + w[m]*x^m
order=1w[0] = 1.0331w[1] = 1.7354
order=2w[0] = 0.2607w[1] = 0.3354w[2] = 1.4000
order=3w[0] = 0.9586w[1] = -0.4745w[2] = -0.3581w[3] = 1.1721
order=4w[0] = 1.0131w[1] = 1.6178w[2] = -1.1039w[3] = -1.5209w[4] = 1.3465

在这里插入图片描述


3.4 Python 例程:样条曲线拟合

程序说明:

  1. scipy.interpolate.UnivariateSpline() 类是一种基于固定数据点创建函数的方法,使用样条曲线拟合到给定的数据点集。
  2. UnivariateSpline 类由已知数据点集生成样条插值函数 y=spl(x),通过调用样条插值函数可以计算指定 x 的函数值 f(x)。
  3. UnivariateSpline 类既可以进行数据插值,也可以进行拟合。参数 s=0 表示数据插值,样条曲线必须通过所有数据点;s>0 表示数据拟合,默认 s= len(w)。
  4. 通过 set_smoothing_factor(sf) 设置光滑因子,可以对样条拟合函数进行调节,使拟合曲线更好地反映观测数据特征,避免过拟合。

Python 例程:

# mathmodel25_v1.py
# Demo25 of mathematical modeling algorithm
# Demo of curve fitting with Scipy
# Copyright 2021 YouCans, XUPT
# Crated:2021-08-03# 5 非线性函数拟合:样条函数拟合(Spline function)
import numpy as np
import matplotlib.pyplot as plt  # 导入 Matplotlib 工具包
from scipy.interpolate import UnivariateSpline  # 导入 scipy 中的样条插值工具# 创建给定数据点集 (x,yObs)
# y = p0 + ((x*x-p1)**2+ p2) * np.sin(x*p3)
np.random.seed(1)
p0, p1, p2, p3 = [1.0, 1.2, 0.5, 0.8]  # 拟合函数的参数
x = np.linspace(-1, 2, 30)  # 生成已知数据点集的 x
y = p0 + ((x*x-p1)**2+ p2) * np.sin(x*p3)  # 生成理论值 y
yObs = y + 0.5*np.random.randn(x.shape[-1])  # 生成带有噪声的观测数据# 由给定数据点集 (x,y) 求拟合函数的参数 fSpl
fSpl = UnivariateSpline(x, yObs)  # 三次样条插值,默认 s= len(w)
coeffs = fSpl.get_coeffs()  # Return spline coefficients
print("Data fitting with spline function")
print("coeffs of 3rd spline function:\n  ", coeffs)# 由拟合函数 fitfunc 计算拟合曲线在数据点的函数值
yFit = fSpl(x)  # 由插值函数 fSpl1 计算插值点的函数值 yFit# 对拟合函数 fitfunc 进行平滑处理
fSpl.set_smoothing_factor(10)  # 设置光滑因子 sf
yS = fSpl(x)   # 由插值函数 fSpl(sf=10) 计算插值点的函数值 ys
coeffs = fSpl.get_coeffs()  # 平滑处理后的参数
print("coeffs of 3rd spline function (sf=10):\n  ", coeffs)# 绘图
fig, ax = plt.subplots(figsize=(8,6))
ax.set_title("Data fitting with spline function")
plt.scatter(x, yObs, label="observed data")
plt.plot(x, y, 'r--', label="theoretical curve")
plt.plot(x, yFit, 'b-', label="3rd spline fitting")
plt.plot(x, yS, 'm-', label="smoothing spline")
plt.legend(loc="best")
plt.show()

程序运行结果:

Data fitting with spline function
coeffs of 3rd spline function:[-0.09707885  3.66083026 -4.20416235  7.95385344]
coeffs of 3rd spline function (sf=10):[0.41218039 0.52795588 1.6248287  0.76540737 8.49462738]

在这里插入图片描述



4. 自定义函数曲线拟合

4.1 scipy.optimize.curve_fit() 函数说明

curve_fit() 使用非线性最小二乘法将自定义的拟合函数拟合到观测数据,不仅可以用于直线、二次曲线、三次曲线的拟合,而且可以适用于任意形式的自定义函数的拟合,使用非常方便。curve_fit() 允许进行单变量或多变量的自定义函数拟合。

**scipy.optimize.curve_fit(f,xdata,ydata,p0=None,sigma=None,absolute_sigma=False,check_finite=True,bounds=(-inf,inf),method=None,jac=None,kwargs) **

主要参数:

  • f:可调用的函数,自定义的拟合函数,具有一个或多个待定参数。拟合函数的形式为 func(x,p1,p2,…),其中参数必须按照 (x,p1,p2,…) 的顺序排列,p1, p2,… 是标量不能表达为数组。
  • xdata:n*m数组,n 为观测数据长度,m为变量个数。观测数据 xdata 可以是一维数组(单变量问题),也可以是多维数组(多变量问题)。
  • ydata:数组,长度为观测数据长度 n。
  • p0:可选项,待定参数 [p1,p2,…] 的初值,默认值无。

返回值:

  • popt:待定参数 (p1,⋯pm)(p_1, \cdots p_m)(p1,pm) 的最小二乘估计值。

  • pcov:参数 (p1,⋯pm)(p_1, \cdots p_m)(p1,pm) 的估计值 popt 的协方差,其对角线是各参数的方差。


4.2 Python 例程:单变量自定义函数曲线拟合

程序说明:

  1. 不同于 leastsq() 定义观测值与拟合函数值的误差函数,scipy.optimize.curve_fit() 直接定义一个自定义的拟合函数,更为直观和便于理解。
  2. curve_fit() 定义一个拟合函数,函数名可以任意定义,但拟合函数的参数必须按照 (x,p1,p2,…) 的顺序排列,不能改变次序。p1, p2,… 是标量,不能写成数组。注意 leastsq() 中误差函数的参数必须按照 (p,x,y) 的顺序排列,与 curve_fit() 不同。
  3. leastsq() 也可以对自定义的拟合函数进行最小二乘拟合。
  4. 由于本例程中自定义拟合函数使用了观测数据的实际模型,而不是通用的多项式函数或样条函数,因此拟合结果不仅能很好的拟合观测数据,而且能更准确地反映实际模型的趋势。

Python 例程:

# 6. 自定义函数曲线拟合:单变量
import numpy as np
import matplotlib.pyplot as plt  # 导入 Matplotlib 工具包
from scipy.optimize import leastsq, curve_fit  # 导入 scipy 中的曲线拟合工具def fitfunc6(x, p0, p1, p2, p3):  # 定义拟合函数为自定义函数# p0, p1, p2, p3 = p  # 拟合函数的参数y = p0 + ((x*x-p1)**2+ p2) * np.sin(x*p3)return y# def error6(p, x, y):  # 定义观测值与拟合函数值的误差函数
#     p0, p1, p2, p3 = p
#     err = fitfunc6(x, p0, p1, p2, p3) - y  # 计算残差
#     return err# 创建给定数据点集 (x, yObs)
p0, p1, p2, p3 = [1.0, 1.2, 0.5, 0.8]  # y = p0 + ((x*x-p1)**2+ p2) * np.sin(x*p3)
x = np.linspace(-1, 2, 30)
y = fitfunc6(x, p0, p1, p2, p3)
np.random.seed(1)
yObs = y + 0.5*np.random.randn(x.shape[-1])  # 生成带有噪声的观测数据# # 用 scipy.optimize.leastsq() 进行函数拟合
# pIni = [1, 1, 1, 1]  # 设置拟合函数的参数初值
# pFit, info = leastsq(error6, pIni, args=(x, yObs))  # 最小二乘法求拟合参数
# print("Data fitting of custom function by leastsq")
# print("y = p0 + ((x*x-p1)**2+ p2) * np.sin(x*p3)")
# print("p[0] = {:.4f}\np[1] = {:.4f}\np[2] = {:.4f}\np[3] = {:.4f}"
#       .format(pFit[0], pFit[1], pFit[2], pFit[3]))# 用 scipy.optimize.curve_fit() 进行自定义函数拟合(单变量)
pFit, pcov = curve_fit(fitfunc6, x, yObs)
print("Data fitting of custom function by curve_fit:")
print("y = p0 + ((x*x-p1)**2+ p2) * np.sin(x*p3)")
print("p[0] = {:.4f}\np[1] = {:.4f}\np[2] = {:.4f}\np[3] = {:.4f}".format(pFit[0], pFit[1], pFit[2], pFit[3]))
print("estimated covariancepcov:\n",pcov)
# 由拟合函数 fitfunc 计算拟合曲线在数据点的函数值
yFit = fitfunc6(x, pFit[0], pFit[1], pFit[2], pFit[3])# 绘图
fig, ax = plt.subplots(figsize=(8,6))
ax.set_title("Data fitting of custom function")
plt.scatter(x, yObs, label="observed data")
plt.plot(x, y, 'r--', label="theoretical curve")
plt.plot(x, yFit, 'b-', label="fitting curve")
plt.legend(loc="best")
plt.show()

程序运行结果:

Data fitting of custom function by curve_fit:
y = p0 + ((x*x-p1)**2+ p2) * np.sin(x*p3)
p[0] = 0.9460
p[1] = 1.1465
p[2] = 0.8291
p[3] = 0.6008
estimated covariancepcov:[[ 0.01341654  0.00523061 -0.01645431  0.00455901][ 0.00523061  0.02648836 -0.04442234  0.02821206][-0.01645431 -0.04442234  0.20326672 -0.07482843][ 0.00455901  0.02821206 -0.07482843  0.0388316 ]]

结果分析:

在这里插入图片描述


4.3 Python 例程:多变量自定义函数曲线拟合

程序说明:

  1. scipy.optimize.curve_fit() 既可以用于单变量也可以用于多变量问题,本例程求解一个二元非线性拟合问题。
  2. curve_fit() 定义一个拟合函数 fitfunc7(X, p0, p1, p2, p3),函数名可以任意定义,但拟合函数的参数必须按照 (x,p1,p2,…) 的顺序排列,不能改变次序。p1, p2,… 是标量,不能写成数组。
  3. curve_fit(fitfunc7, X, yObs) 中的 X 是 (n,m) 数组,n 是观测数据点集的长度,m 是变量个数。

Python 例程:

# mathmodel25_v1.py
# Demo25 of mathematical modeling algorithm
# Demo of curve fitting with Scipy
# Copyright 2021 YouCans, XUPT
# Crated:2021-08-03# 7. 自定义函数曲线拟合:多变量
import numpy as np
import matplotlib.pyplot as plt  # 导入 Matplotlib 工具包
from scipy.optimize import curve_fit  # 导入 scipy 中的曲线拟合工具def fitfunc7(X, p0, p1, p2, p3):  # 定义多变量拟合函数, X 是向量# p0, p1, p2, p3 = p  # 拟合函数的参数y = p0 + p1*X[0,:] + p2*X[1,:] + p3*np.sin(X[0,:]+X[1,:]+X[0,:]**2+X[1,:]**2)return y# 创建给定数据点集 (x,yObs)
p = [1.0, 0.5, -0.5, 5.0]  # 自定义函数的参数
p0, p1, p2, p3 = p  # y = p0 + p1*x1 + p2*x2 + p3*np.sin(x1+x2+x1^2+x2^2)
np.random.seed(1)
x1 = 2.0 * np.random.rand(8)  # 生成随机数组,长度为 8
x2 = 3.0 * np.random.rand(5)  # 生成随机数组,取值范围 (0,3.0)
xmesh1, xmesh2 = np.meshgrid(x1, x2)  # 生成网格点的坐标 xx,yy (二维数组)
xx1= xmesh1.reshape(xmesh1.shape[0]*xmesh1.shape[1], )  # 将网格点展平为一维数组
xx2= xmesh2.reshape(xmesh2.shape[0]*xmesh2.shape[1], )  # 将网格点展平为一维数组
X = np.vstack((xx1,xx2))  # 生成多变量数组,行数为变量个数
y = fitfunc7(X, p0, p1, p2, p3)  # 理论计算值 y=f(X,p)
yObs = y + 0.2*np.random.randn(y.shape[-1])  # 生成带有噪声的观测数据
print(x1.shape,x2.shape,xmesh1.shape,xx1.shape,X.shape)# 用 scipy.optimize.curve_fit() 进行自定义函数拟合(多变量)
pFit, pcov = curve_fit(fitfunc7, X, yObs)  # 非线性最小二乘法曲线拟合
print("Data fitting of multivariable custom function")
print("y = p0 + p1*x1 + p2*x2 + p3*np.sin(x1+x2+x1^2+x2^2)")
for i in range(4):print("p[{:d}] = {:.4f}\tp[{:d}]_fit = {:.4f}".format(i, p[i], i, pFit[i]))# 由拟合函数 fitfunc 计算拟合曲线在数据点的函数值
yFit = fitfunc7(X, pFit[0], pFit[1], pFit[2], pFit[3])

程序运行结果:

Data fitting of multivariable custom function:
y = p0 + p1*x1 + p2*x2 + p3*np.sin(x1+x2+x1^2+x2^2)
p[0] = 1.0000	p[0]_fit = 1.1316
p[1] = 0.5000	p[1]_fit = 0.5020
p[2] = -0.5000	p[2]_fit = -0.5906
p[3] = 5.0000	p[3]_fit = 5.0061
estimated covariancepcov:[[ 9.51937904e-03 -2.82863223e-03 -5.26393413e-03 -8.51457970e-04][-2.82863223e-03  4.88275894e-03  9.39281331e-05  3.73832161e-04][-5.26393413e-03  9.39281331e-05  3.86701646e-03  4.65766686e-04][-8.51457970e-04  3.73832161e-04  4.65766686e-04  1.85374067e-03]]

在这里插入图片描述



【本节完】


版权声明:

欢迎关注『Python小白的数学建模课 @ Youcans』 原创作品

原创作品,转载必须标注原文链接:(https://blog.csdn.net/youcans/article/details/119332590)。

Copyright 2021 Youcans, XUPT

Crated:2021-08-05


欢迎关注 『Python小白的数学建模课 @ Youcans』 系列,持续更新
Python小白的数学建模课-01.新手必读
Python小白的数学建模课-02.数据导入
Python小白的数学建模课-03.线性规划
Python小白的数学建模课-04.整数规划
Python小白的数学建模课-05.0-1规划
Python小白的数学建模课-06.固定费用问题
Python小白的数学建模课-07.选址问题
Python小白的数学建模课-09.微分方程模型
Python小白的数学建模课-10.微分方程边值问题
Python小白的数学建模课-12.非线性规划
Python小白的数学建模课-15.图论的基本概念
Python小白的数学建模课-16.最短路径算法
Python小白的数学建模课-17.条件最短路径算法
Python小白的数学建模课-18.最小生成树问题
Python小白的数学建模课-19.网络流优化问题
Python小白的数学建模课-20.网络流优化案例
Python小白的数学建模课-21.关键路径法
Python小白的数学建模课-22.插值方法
Python小白的数学建模课-23.数据拟合全集
Python小白的数学建模课-A1.国赛赛题类型分析
Python小白的数学建模课-A2.2021年数维杯C题探讨
Python小白的数学建模课-A3.12个新冠疫情数模竞赛赛题及短评
Python小白的数学建模课-B2. 新冠疫情 SI模型
Python小白的数学建模课-B3. 新冠疫情 SIS模型
Python小白的数学建模课-B4. 新冠疫情 SIR模型
Python小白的数学建模课-B5. 新冠疫情 SEIR模型
Python小白的数学建模课-B6. 新冠疫情 SEIR改进模型
Python数模笔记-PuLP库
Python数模笔记-StatsModels统计回归
Python数模笔记-Sklearn
Python数模笔记-NetworkX
Python数模笔记-模拟退火算法

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/566100.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Css背景

Css背景 1.背景图像:background-image 要把图像放入背景,需要使用background-image 属性。background-image属性的默认值是 none,表示背景上没有放置任何图像。 如果需要设置一个背景图像,必须为这个属性设置一个 URL值&#xff…

Python小白的数学建模课-11.偏微分方程数值解法

偏微分方程可以描述各种自然和工程现象, 是构建科学、工程学和其他领域的数学模型主要手段。 偏微分方程主要有三类:椭圆方程,抛物方程和双曲方程。 本文采用有限差分法求解偏微分方程,通过案例讲解一维平流方程、一维热传导方程…

Css语法

Css语法 如果值为若干个单词,加引号 p {font-family: “sans serif”;} 多重声明:分号隔开 如果要定义不止一个声明,则需要用分号把声明隔开。如 p {text-align:center; color:red;} 你应该在每行只描述一个属性,这样可以增强…

A4.2021年全国数学建模竞赛A题-赛题分析与评阅要点(FAST主动反射面的形状调节)

Python小白的数学建模课-A4.2021年全国数学建模竞赛A题(FAST主动反射面的形状调节),本文转载竞赛赛题、评阅要点,进行赛题解读和分析。 评阅要点为竞赛组委会官方公布,完整体现了解题思路。 『Python小白的数学建模课…

Css字体

Css字体 使用像素 Firefox,Chrome,and Safari中文本大小可调节,而ie不行 使用em em可以解决在ie中浏览器显示文本的问题。w3c推荐用em作为尺寸单位。 1em等于当前的字体尺寸,如果一个元素的font-size为16像素,那么对…

A5.2021年全国数学建模竞赛B题-赛题分析与评阅要点(乙醇偶合制备C4烯烃分析)

A5.2021年全国数学建模竞赛B题-赛题分析与评阅要点(乙醇偶合制备C4烯烃分析),本文转载竞赛赛题、评阅要点,进行赛题解读和分析。 评阅要点为竞赛组委会官方公布,完整体现了解题思路。 本文首发于 2021年9月8日&#…

emmet插件使用(Css)

emmet插件使用(Css) 渐变 输入lg(left,#fff50%,#000),会生成如下代码 background-image: -webkit-gradient(linear, 0 0, 100% 0, color-stop(0.5, #fff), to(#000)); background-image: -webkit-linear-gradient(left, #fff 50%, #000); background-image: -moz-linear-gradie…

Python 小白从零开始 PyQt5 项目实战(1)安装与环境配置

本系列面向 Python 小白,从零开始实战解说应用 QtDesigner 进行 PyQt5 的项目实战。 什么叫从零开始?从软件安装、环境配置开始。 不跳过一个细节,不漏掉一行代码,不省略一个例图。 欢迎关注『Python 小白从零开始 PyQt5 项目实战…

emmet使用(HTML)

emmet使用(HTML) htmlTab直接生成固定标签 <!DOCTYPE html> <html> <head> <title></title> </head> <body> </body> 分组&#xff1a;可以通过嵌套来快速生成一些代码块 (.foo>h1)(.bar>h2) 隐式标签 在过去的版本中省…

Python 小白从零开始 PyQt5 项目实战(2)菜单和工具栏

本系列面向 Python 小白&#xff0c;从零开始实战解说应用 QtDesigner 进行 PyQt5 的项目实战。 什么叫从零开始&#xff1f;从软件安装、环境配置开始。不跳过一个细节&#xff0c;不漏掉一行代码&#xff0c;不省略一个例图。 本文详细解读通过 QtDesigner 创建主窗口、菜单栏…

Python 小白从零开始 PyQt5 项目实战(3)信号与槽的连接

本系列面向 Python 小白&#xff0c;从零开始实战解说应用 QtDesigner 进行 PyQt5 的项目实战。 什么叫从零开始&#xff1f;从软件安装、环境配置开始。不跳过一个细节&#xff0c;不漏掉一行代码&#xff0c;不省略一个例图。 本文讲解信号与槽的连接机制&#xff0c;详细示范…

Css内边距与外边距

Css内边距与外边距 Css内边距 Css外边距margin Css外边距margin 设置外边距最简单的方法就是margin属性。margin属性接受任何长度单位&#xff0c;可以是像素&#xff0c;英寸&#xff0c;毫米或em margin可以设置为auto。更常见的做法就是为外边距设置长度值。下面的声明在h1…

Python 小白从零开始 PyQt5 项目实战(4)基本控件

本系列面向 Python 小白&#xff0c;从零开始实战解说应用 QtDesigner 进行 PyQt5 的项目实战。 什么叫从零开始&#xff1f;从软件安装、环境配置开始。不跳过一个细节&#xff0c;不漏掉一行代码&#xff0c;不省略一个例图。 PyQt5 提供了丰富的输入输出控件。本文介绍通过 …

Python 小白从零开始 PyQt5 项目实战(5)布局管理

本系列面向 Python 小白&#xff0c;从零开始实战解说应用 QtDesigner 进行 PyQt5 的项目实战。 什么叫从零开始&#xff1f;从软件安装、环境配置开始。不跳过一个细节&#xff0c;不漏掉一行代码&#xff0c;不省略一个例图。 布局管理就是管理图形窗口中各个部件的位置和排列…

Css外边距合并

Css外边距合并 外边距合并是一个相当简单的概念&#xff0c;但是&#xff0c;在实践中对网页进行布局时&#xff0c;它会造成许多混淆。 简单的说&#xff0c;外边距合并指的是&#xff0c;当两个垂直外边距相遇时&#xff0c;它们将形成一个外边距。合并后的外边距的高度等于两…

Python 小白从零开始 PyQt5 项目实战(6)窗口切换的堆叠布局

本系列面向 Python 小白&#xff0c;从零开始实战解说应用 QtDesigner 进行 PyQt5 的项目实战。 软件项目中经常需要多种不同的图形界面&#xff0c;以适应不同的任务场景。选项卡控件&#xff08;QTackedWidget&#xff09;通过标签选择打开对应的对话框页面&#xff0c;不需要…

Css链接

Css链接 四种状态 当为链接的不同状态设置样式时&#xff0c;请按照以下次序的规则&#xff1a; a:hover必须位于a:link和a:visited之后&#xff0c;a:active必须位于a:hover之后 文本修饰 text-decoration属性大多用于去掉链接中的下划线 a:link{text-decoration:none;} a:li…

Python 小白从零开始 PyQt5 项目实战(7)折叠侧边栏的实现

单式状态栏&#xff0c;位于于窗口的左右侧边&#xff0c;可以实现软件功能或目录的导航。 本文详细介绍用 QTreeWidget 部件实现目录结构的折叠侧边栏&#xff0c;与用 QToolBox 部件实现垂直菜单结构的折叠侧边栏&#xff0c;通过案例带小白建立两种典型的折叠侧边栏。 至此&…

Css轮廓

Css轮廓 轮廓是绘制于元素周围的一条线&#xff0c;位于边缘的外围&#xff0c;可起到突出元素的作用。Css outline属性规定元素轮廓的样式&#xff0c;颜色和宽度 outline p{ outline:#00FF00 dotted thick; }

Python 小白从零开始 PyQt5 项目实战(8)汇总篇(完整例程)

本系列面向 Python 小白&#xff0c;从零开始实战解说应用 QtDesigner 进行 PyQt5 的项目实战。不跳过一个细节&#xff0c;不漏掉一行代码&#xff0c;不省略一个例图。 本系列从软件安装、环境配置开始&#xff0c;介绍了基本应用&#xff1a;菜单和工具栏、基本控件&#xf…