数学建模-用scipy.optimize的模块的curve_fit函数实现曲线的非线性最小二乘法拟合


这里我们用经典的人口预测模型来进行函数的使用说明

美国人口预测模型

栗题:

利用下表给出的近两个世纪的美国人口统计数据(以百万为单位),建立人口预测模型,最后用它估计2010年美国的人口.

年份 1790 1800 1810 1820 1830 1840 1850 1860
人口 3.9 5.3 7.2 9.6 12.9 17.1 23.2 31.4
年份 1870 1880 1890 1900 1910 1920 1930 1940
人口 38.6 50.2 62.9 76.0 92.0 106.5 123.2 131.7
年份 1950 1960 1970 1980 1990 2000
人口 150.7 179.3 204.0 226.5 251.4 281.4

建模与求解

x ( t ) x(t) x(t)为第t年的人口数量,设人口年增长率r(x)为x的线性函数, r ( x ) = r − s x r(x)=r-sx r(x)=rsx.自然资源与环境条件所能容纳的最大人口数为 x m x_m xm,即当 x = x m x=x_m x=xm时,增长率 r ( x m ) r(x_m) r(xm)=0,可得 r ( x ) = r ( 1 − x x m ) r(x)=r(1-\frac{x}{x_m}) r(x)=r(1xmx),建立logistic人口模型: x ( t ) = x m 1 + ( x m x 0 − 1 ) e − r ( t − t 0 ) x(t)=\frac{xm}{1+(\frac{xm}{x0}-1)e^{-r(t-t0)}} x(t)=1+(x0xm1)er(tt0)xm

参数估计

  1. 非线性最小二乘法

把上表中的第1个数据作为初始条件,利用余下的数据拟合式(8.23)中的参数 x m x_m xm r r r

在我的资源里面数据已经用pandas处理过Pdata8_10_1.txt.

用python进行拟合

import numpy as np
from scipy.optimize import curve_fit
a=[]; b=[];
with open("Pdata8_10_1.txt") as f:    #打开文件并绑定对象f 使用with执行文件操作不用担心资源的释放问题,python会在合适的时间将其自动释放
    s=f.read().splitlines()  #返回每一行的数据
for i in range(0, len(s),2):  #读入奇数行数据
    d1=s[i].split("\t")
    for j in range(len(d1)):
        if d1[j]!="": a.append(eval(d1[j]))  #把非空的字符串转换为年代数据
for i in range(1, len(s), 2):  #读入偶数行数据
    d2=s[i].split("\t")
    for j in range(len(d2)):
        if d2[j] != "": b.append(eval(d2[j])) #把非空的字符串转换为人口数据
c=np.vstack((a,b))  #构造两行的数组
x=lambda t, r, xm: xm/(1+(xm/3.9-1)*np.exp(-r*(t-1790))) #用匿名函数表示我们前面算出的函数表达式
bd=((0, 200), (0.1,1000))  #约束两个参数的下界和上界
popt, pcov=curve_fit(x, a[1:], b[1:], bounds=bd)
print(popt); print("2010年的预测值为:", x(2010, *popt))#*parameters表示接受一个放有多个元素的元组

输出:

[2.73527906e-02 3.42441912e+02]
2010年的预测值为: 282.67978310482215

scipy.optimize curve_fit函数

大家可以看到,整个代码中最核心的就是scipy.optimize模块中的curve_fit函数,下面我们就来详解一下它.

def curve_fit(f, xdata, ydata, p0=None, sigma=None, absolute_sigma=False,
              check_finite=True, bounds=(-np.inf, np.inf), method=None,
              jac=None, **kwargs):
    """
函数作用: Use non-linear least squares to fit a function, f, to data.

我们只研究里面几个重要的参数能够方便我们进行使用:
f:

callable
    The model function, f(x, ...).  It must take the independent
    variable as the first argument and the parameters to fit as
    separate remaining arguments.
    f就是我们需要拟合的函数 这没什么好说的,一般都是用匿名函数进行定义

xdata:

xdata : An M-length sequence or an (k,M)-shaped array for functions with k predictors
    The independent variable where the data is measured.
    可以看到x需要传入一个有k个需要预测的变量且有长度为M的数据的数组 
    而这里我们只有t,需要拟合r和xm,所以在上面代码中因为我们只能传入一个变量的数据 也就是时间t 所以我们的K是1 也就是一维数组

ydata:

ydata : M-length sequence
    The dependent data --- nominally f(xdata, ...)
    因为是函数的值(也就是y的值)所以必须是一维数组了
    需要注意的是这里的长度必须和x的长度一样,原因都懂吧

bounds

bounds : 2-tuple of array_like, optional
    Lower and upper bounds on parameters. Defaults to no bounds.
    Each element of the tuple must be either an array with the length equal
    to the number of parameters, or a scalar (in which case the bound is
    taken to be the same for all parameters.) Use ``np.inf`` with an
    appropriate sign to disable bounds on all or some parameters.
    w
    
    这里我们有几个需要拟合的参数就传入几个有两个值的数组组合成一个元组,格式就像上面的代码一样
    bd=((0, 200), (0.1,1000)) 

还有几个参数例如sigma等就是拟合的方式的问题,这个涉及到数学知识,这里我们就不多赘述.

返回值:

popt : array
    Optimal values for the parameters so that the sum of the squared
    residuals of ``f(xdata, *popt) - ydata`` is minimized
pcov : 2d array
    The estimated covariance of popt. The diagonals provide the variance
    of the parameter estimate. To compute one standard deviation errors
    on the parameters use ``perr = np.sqrt(np.diag(pcov))``.

    How the `sigma` parameter affects the estimated covariance
    depends on `absolute_sigma` argument, as described above.

    If the Jacobian matrix at the solution doesn't have a full rank, then
    'lm' method returns a matrix filled with ``np.inf``, on the other hand
    'trf'  and 'dogbox' methods use Moore-Penrose pseudoinverse to compute
    the covariance matrix.

返回值就两个,主要关注第一个

  1. f(xdata, *popt) - ydata 我们传入一个参数的数据,其返回的就是使得y最小的剩下的参数的值组成一个数组

  2. 第二个返回的协方差 同样涉及到数学知识,不多说

猜你喜欢

转载自blog.csdn.net/weixin_45870904/article/details/113151013