优化是指在某些约束条件下,求解目标函数最优解的过程。机器学习、人工智能中的绝大部分问题都会涉及到求解优化问题。

SciPy的optimize模块提供了许多常用的数值优化算法,一些经典的优化算法包括线性回归、函数极值和根的求解以及确定两函数交点的坐标等。

导入scipy.optimize模块,如下所示:

from scipy import optimize

标量函数极值求解

fmin_bfgs方法

函数f(x)是一个抛物线,求它的极小值:

$$

f(x) = x^2 + 2x + 9

$$

我们先画出函数曲线:

import numpy as np
from scipy import optimize
import matplotlib.pyplot as plt # 定义函数
def f(x):
return x**2 + 2*x + 9 # x取值:-10到10之间,间隔0.1
x = np.arange(-10, 10, 0.1) # 画出函数曲线
plt.plot(x, f(x))
# plt.savefig('./opt2-1.png') # 保存要显示的图片
plt.show()

计算该函数最小值的有效方法之一是使用带起点的BFGS算法。该算法从参数给定的起始点计算函数的梯度下降,并输出梯度为零、二阶导数为正的极小值。BFGS算法是由Broyden,Fletcher,Goldfarb,Shanno四个人分别提出的,故称为BFGS校正。

示例

使用BFGS函数,找出抛物线函数的最小值:

import numpy as np
from scipy import optimize
import matplotlib.pyplot as plt # 定义函数
def f(x):
return x**2 + 2*x + 9 # x取值:-10到10之间,间隔0.1
x = np.arange(-10, 10, 0.1) # 画出函数曲线
plt.plot(x, f(x)) # 第一个参数是函数名,第二个参数是梯度下降的起点。返回值是函数最小值的x值(ndarray数组)
xopt = optimize.fmin_bfgs(f, 0) xmin = xopt[0] # x值
ymin = f(xmin) # y值,即函数最小值
print('xmin: ', xmin)
print('ymin: ', ymin) # 画出最小值的点, s=20设置点的大小,c='r'设置点的颜色
plt.scatter(xmin, ymin, s=20, c='r') #plt.savefig('./opt3-1.png') # 保存要显示的图片
plt.show()

输出


Optimization terminated successfully.
Current function value: 8.000000
Iterations: 2
Function evaluations: 9
Gradient evaluations: 3
xmin: -1.00000000944232
ymin: 8.0

fmin_bfgs有个问题,当函数有局部最小值,该算法会因起始点不同,找到这些局部最小而不是全局最小。

让我们看另一个函数,该函数有多个局部最小值:

$$

g(x) = x^2 + 20sin(x)

$$

画出该函数的曲线:

import numpy as np
from scipy import optimize
import matplotlib.pyplot as plt # 定义函数
def g(x):
return x**2 + 20*np.sin(x) # x取值:-10到10之间,间隔0.1
x = np.arange(-10, 10, 0.1) # 画出函数曲线
plt.plot(x, g(x))
# plt.savefig('./opt4-1.png') # 保存要显示的图片
plt.show()

函数曲线

可以看到,该函数有多个底部。如果初始值设置不当,获得的最小值有可能只是局部最小值。

import numpy as np
from scipy import optimize
import matplotlib.pyplot as plt # 定义函数
def g(x):
return x**2 + 20*np.sin(x) # x取值:-10到10之间,间隔0.1
x = np.arange(-10, 10, 0.1) # 画出函数曲线
plt.plot(x, g(x)) # 第一个参数是函数名,第二个参数是梯度下降的起点。返回值是函数最小值的x值(ndarray数组)
# 可以看到5.0附近有个局部最小,把初始值设置为7, 返回的应该是这个局部最小值。
xopt = optimize.fmin_bfgs(g, 7) xmin = xopt[0] # x值
ymin = g(xmin) # y值,即函数最小值
print('xmin: ', xmin)
print('ymin: ', ymin) # 画出最小值的点, s=20设置点的大小,c='r'设置点的颜色
plt.scatter(xmin, ymin, s=20, c='r') #plt.savefig('./opt5-1.png') # 保存要显示的图片
plt.show()

输出

Optimization terminated successfully.
Current function value: 0.158258
Iterations: 3
Function evaluations: 27
Gradient evaluations: 9
xmin: 4.271095444673479
ymin: 0.15825752683190686

可以看到5.0附近有个局部最小,把初始值设置为7, 返回的是这个局部最小值。

如果把初始值设置为0,应该就能返回真正的全局最小值:

basinhopping 方法

对于这种情况,可以使用scipy.optimize提供的basinhopping()方法。该方法把局部优化方法与起始点随机抽样相结合,求出全局最小值,代价是耗费更多计算资源。

调用语法

optimize.basinhopping(func, x0)
  • func 目标函数
  • x0 初始值

示例

import numpy as np
from scipy import optimize # 定义函数
def g(x):
return x**2 + 20*np.sin(x) # 求取最小值,初始值为7
ret = optimize.basinhopping(g, 7) print(ret)

输出

                        fun: 0.15825752683178962
lowest_optimization_result: fun: 0.15825752683178962
hess_inv: array([[0.04975718]])
jac: array([4.76837158e-07])
message: 'Optimization terminated successfully.'
nfev: 12
nit: 2
njev: 4
status: 0
success: True
x: array([4.27109533])
message: ['requested number of basinhopping iterations completed successfully']
minimization_failures: 0
nfev: 1641
nit: 100
njev: 547
x: array([4.27109533])

可以看到全局最小值被正确找出:fun: 0.15825752683178962x: array([4.27109533])

scipy.optimize.brute函数蛮力法也可用于全局优化,但效率较低。蛮力方法的语法为:

scipy.optimize.brute(f, 0)

fminbound

要求取一定范围之内的函数最小值,可使用fminbound方法。

调用语法

optimize.fminbound(func, x1, x2)
  • func 目标函数
  • x1, x2 范围边界

示例

import numpy as np
from scipy import optimize # 定义函数
def g(x):
return x**2 + 20*np.sin(x) # 求取-10到-5之间的函数最小值。full_output=True表示返回详细信息。
ret = optimize.fminbound(g, -10, -5, full_output=True) print(ret)

输出

(-7.068891380019064, 35.82273589215206, 0, 12)

函数最小值是:35.82273589215206,对应的x值:-7.068891380019064。

函数求解

对于一个函数f(x),当f(x) = 0,求取x的值,即为函数求解。这种情况,可以使用fsolve()函数。

调用语法

optimize.fsolve(func, x0)
  • func 目标函数
  • x0 初始值

解单个方程

示例

解单个方程:

import numpy as np
from scipy import optimize # 定义函数
def g(x):
return x**2 + 20*np.sin(x) # 函数求解
ret = optimize.fsolve(g, 2) print(ret)

输出

[0.]

解出的根值是:0

解方程组

如果要对如下方程组求解:

$$

f1(u1,u2,u3) = 0 \

f2(u1,u2,u3) = 0 \

f3(u1,u2,u3) = 0

$$

func可以定义为:

def func(x):
u1,u2,u3 = x
return [f1(u1,u2,u3), f2(u1,u2,u3), f3(u1,u2,u3)]

示例

解方程组:

$$

4x + 9 = 0 \

3y^2 - sin(yz) = 0 \

yz - 2.5 = 0

$$

from scipy.optimize import fsolve
from math import sin,cos def f(x):
x0 = float(x[0])
x1 = float(x[1])
x2 = float(x[2])
return [
4*x1 + 9,
3*x0*x0 - sin(x1*x2),
x1*x2 - 2.5
]
result = fsolve(f, [1,1,1])
print (result)

输出

[-0.44664383 -2.25       -1.11111111]

拟合

curve_fit

假设有一批数据样本,要创建这些样本数据的拟合曲线/函数,可以使用Scipy.optimize模块的curve_fit()函数。

调用形式

optimize.curve_fit(func, x1, y1)
  • func 目标函数
  • x1, y1 样本数据

我们将使用下面的函数来演示曲线拟合:

$$

f(x) = 50cos(x) + 2

$$

示例

import numpy as np
from scipy import optimize
import matplotlib.pyplot as plt # 函数模型用于生成数据
def g(x, a, b):
return a*np.cos(x) + b # 产生含噪声的样本数据
x_data = np.linspace(-5, 5, 100) # 采样点
y_data = g(x_data, 50, 2) + 5*np.random.randn(x_data.size) # 加入随机数作为噪声 # 使用curve_fit()函数来估计a和b的值
variables, variables_covariance = optimize.curve_fit(g, x_data, y_data) # 输出结果
print('\n求出的系数a, b: ')
print(variables) print('\nvariables_covariance: ')
print(variables_covariance)

输出


求出的系数a, b:
[49.66367999 2.09557981] variables_covariance:
[[0.55593391 0.10388677]
[0.10388677 0.26071478]]

variables是给定模型的最优参数,variables_covariance可用于检查拟合情况,其对角线元素值表示每个参数的方差。可以看到我们正确求出了系数值。

绘制曲线:


import matplotlib.pyplot as plt y = g(x_data, variables[0], variables[1]) plt.plot(x_data, y_data, 'o', color="green", label = "Samples")
plt.plot(x_data, y, color="red", label = "Fit")
plt.legend(loc = "best") #plt.savefig('./opt10-1.png') # 保存要显示的图片
plt.show()

生成

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-98kPUfcs-1571731570441)(https://www.qikegu.com/wp-content/uploads/2019/07/opt10-1.png)]

leastsq()函数

最小二乘法是非常经典的数值优化算法,通过最小化误差的平方和来寻找最符合数据的曲线。

optimize模块提供了实现最小二乘拟合算法的函数leastsq(),leastsq是least square的简写,即最小二乘法。

调用形式

optimize.leastsq(func, x0, args=())
  • func 计算误差的函数
  • x0 是计算的初始参数值
  • args 是指定func的其他参数

示例

import numpy as np
from scipy import optimize # 样本数据
X = np.array([160,165,158,172,159,176,160,162,171]
Y = np.array([58,63,57,65,62,66,58,59,62]) # 偏差函数, 计算以p为参数的直线和原始数据之间的误差
def residuals(p):
k, b = p
return Y-(k*X+b) # leastsq()使得residuals()的输出数组的平方和最小,参数的初始值为[1, 0]
ret = optimize.leastsq(residuals, [1, 10])
k, b = ret[0]
print("k = ", k, "b = ", b)

输出

k = 0.4211697393502931 b = -8.288302606523974

绘制曲线:


import matplotlib.pyplot as plt #画样本点
plt.figure(figsize=(8, 6)) ##指定图像比例: 8:6
plt.scatter(X, Y, color="green", label="Samples", linewidth=2) #画拟合直线
x = np.linspace(150, 190, 100) ##在150-190直接画100个连续点
y = k*x + b ##函数式
plt.plot(x,y,color="red", label="Fit",linewidth=2)
plt.legend() #绘制图例
plt.savefig('./opt11-1.png') # 保存要显示的图片
plt.show()

输出

SciPy 优化的更多相关文章

  1. python scipy优化器模块(optimize)

    pyhton数据处理与分析之scipy优化器及不同函数求根 1.Scipy的优化器模块optimize可以用来求取不同函数在多个约束条件下的最优化问题,也可以用来求取函数在某一点附近的根和对应的函数值 ...

  2. scipy优化器optimizer

    #optimazer优化器 from scipy.optimize import minimize def rosem(x): return sum(100.0*(x[1:]-x[:-1])**2.0 ...

  3. Scipy优化算法--scipy.optimize.fmin_tnc()/minimize()

    scipy中的optimize子包中提供了常用的最优化算法函数实现,我们可以直接调用这些函数完成我们的优化问题. scipy.optimize包提供了几种常用的优化算法. 该模块包含以下几个方面 使用 ...

  4. 第4天:scipy库

    一.SciPy库概述 1.numpy提供向量和矩阵的相关操作,高级计算器 2.SciPy在统计.优化.插值.数值积分.视频转换等,涵盖基础科学计算相关问题. (额,对统计和概率,数理完全一窍不通) 3 ...

  5. SciPy 信号处理

    章节 SciPy 介绍 SciPy 安装 SciPy 基础功能 SciPy 特殊函数 SciPy k均值聚类 SciPy 常量 SciPy fftpack(傅里叶变换) SciPy 积分 SciPy ...

  6. SciPy 统计

    章节 SciPy 介绍 SciPy 安装 SciPy 基础功能 SciPy 特殊函数 SciPy k均值聚类 SciPy 常量 SciPy fftpack(傅里叶变换) SciPy 积分 SciPy ...

  7. SciPy 线性代数

    章节 SciPy 介绍 SciPy 安装 SciPy 基础功能 SciPy 特殊函数 SciPy k均值聚类 SciPy 常量 SciPy fftpack(傅里叶变换) SciPy 积分 SciPy ...

  8. SciPy 图像处理

    章节 SciPy 介绍 SciPy 安装 SciPy 基础功能 SciPy 特殊函数 SciPy k均值聚类 SciPy 常量 SciPy fftpack(傅里叶变换) SciPy 积分 SciPy ...

  9. SciPy 积分

    章节 SciPy 介绍 SciPy 安装 SciPy 基础功能 SciPy 特殊函数 SciPy k均值聚类 SciPy 常量 SciPy fftpack(傅里叶变换) SciPy 积分 SciPy ...

随机推荐

  1. JS 上传图片压缩,原比例压缩

    复制 粘贴 改吧改吧就可用,原生js var fileObj = file.file;//原文件 file是我用vue-vant里的组件,里边有file(原文件)和content(base64) 其它 ...

  2. 关于Debug Assertion Failed问题

    书上代码: #include<stdio.h> #include<stdlib.h> /* 提供malloc().free()函数 */ #include<string. ...

  3. sftp和FTP

    sftp 是一个交互式安全文件传输协议的传输程式.它类似于 ftp也叫internet网络文件协议, 但它进行加密传输,比FTP有更高的安全性.下边就简单介绍一下如何远程连接主机,进行文件的上传和下 ...

  4. JavaScript - map和parseInt的坑

    问题: var arrs = ['1', '2', '3']; var r = arrs.map(parseInt); alert(r);//1,NaN,NaN map arr.map(functio ...

  5. SpringBoot笔记二:整合篇

    Spring Boot与缓存 jsr-107 Java Caching定义了5个核心接口分别是CachingProvider, CacheManager, Cache, Entry 和 Expiry. ...

  6. 吴裕雄 Bootstrap 前端框架开发——Bootstrap 排版:引导主体副本

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  7. 报错PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target"

    今天在调用第三方HTTPS接口的时候,一直显示这个报错,然后百度很久,有2种解决方法,一个是说自己手动去导入,第二种用代码忽略证书验证.我用二种方式, 复制即用, public void test2( ...

  8. Netcat - 网络工具中的瑞士军刀

    nc的一些小应用,慢更新.... 1.一个简单的聊天工具,Client1和Client2之间,Client1安装了nc,监听8888端口,Client2用telnet Client1的8888端口即可 ...

  9. 3_01_MSSQL课程_Ado.Net_连接数据库

    1. Ado.Net 是一组微软的c#操作数据库的类库. 2.开发人员将界面上的数据(用户的操作和输入的数据)存储到数据库当中.. 3.数据库访问的驱动.即:应用程序和数据库的桥梁. 4.驱动层. S ...

  10. tensorflow变量的使用(02-2)

    import tensorflow as tf x=tf.Variable([1,2]) a=tf.constant([3,3]) sub=tf.subtract(x,a) #增加一个减法op add ...