Python 代码优化:如何使用scipy最小化优化代码?

Python 代码优化:如何使用scipy最小化优化代码?,python,python-3.x,scipy-optimize,Python,Python 3.x,Scipy Optimize,我试图优化我编写的代码,以计算方程组的最小二乘,并返回未知量的最佳值:a1、a2、a3、z1、z2(pottemp和zlevels已知) 方程组如下(): 我写了下面的代码,它工作起来很有魅力,但是它不是很有效,你可以看到由于for循环的数量,如果我增加hstep和astep的数量,我的数组会变得非常大,从leastsquared计算最小二乘需要很多时间 def leastsquared(zlevels,pottemp,z1,z2,a1,a2,a3): dtot=0.0 对于范围内的zi(le

我试图优化我编写的代码,以计算方程组的最小二乘,并返回未知量的最佳值:
a1、a2、a3、z1、z2
pottemp
zlevels
已知)

方程组如下():

我写了下面的代码,它工作起来很有魅力,但是它不是很有效,你可以看到由于for循环的数量,如果我增加
hstep
astep
的数量,我的数组会变得非常大,从
leastsquared
计算最小二乘需要很多时间

def leastsquared(zlevels,pottemp,z1,z2,a1,a2,a3):
dtot=0.0
对于范围内的zi(len(zlevels)):#zOBS点的值

如果zlevels[zi]我不太确定实际变量及其值。但以下是我尝试过的东西:

import numpy as np
from scipy.optimize import minimize

def leastsquared(zlevels,pottemp,z1,z2,a1,a2,a3):
    dtot=0.0
    for zi in range(len(zlevels)): #zvalue of obs points 
        if zlevels[zi]<=z1:
            F = np.tan(a1)*zlevels[zi]+pottemp[0]
        elif zlevels[zi]<=z2:
            F = (np.tan(a1)*z1+pottemp[0]) + np.tan(a2)*(zlevels[zi]-z1)
        else: #zlevels[zi]<=H
            F=((np.tan(a1)*z1+pottemp[0]) + np.tan(a2)*(z2-z1) ) + np.tan(a3)*(zlevels[zi]-z2)
        d=(pottemp[zi]-F)**2.0
        dtot+=d
    dtot=dtot/len(zlevels)
    #print("dtot is" + str(dtot))
    return dtot

def optm(hstep,astep,zlevels,pottemp):
    steps = np.linspace(0,0.01,astep)
    x0 = np.array([steps, steps, steps]) #a1, a2, a3

    def objective(x):
        return leastsquared(zlevels,pottemp, z1, z2, x[0], x[1], x[2])

    sqdist=np.inf
    for z1 in np.linspace(0,zlevels[-1],hstep):
        for z2 in np.linspace(0,zlevels[-1],hstep):
            sol = minimize(objective, x0, method='SLSQP', options={'disp':True})
            optimalsetting=[z1,z2,sol.x[0],sol.x[1],sol.x[2]]
    return optimalsetting


# test
# some random initialization
astep = 2
steps = 3


optm(5, 2, [1, 2], [1, 2])
将numpy导入为np
从scipy.optimize导入最小化
def最小平方(zlevels、pottemp、z1、z2、a1、a2、a3):
dtot=0.0
对于范围内的zi(len(zlevels)):#zOBS点的值

如果zlevels[zi]肯定有一种更有效的方法来处理这个问题,因为分段线性问题已经得到了很好的研究,但是下面是根据要求使用
scipy.optimize
完成的。此外,scipy无法处理动态约束,例如要求
z1它工作得很好,但在我的例子中,我需要找到最小二乘法的最小值(对于
z1、z2、a1、a2、a3的最佳值,因此它适合我的数据)。这在
opt
if sqdist_newt那太好了!但是我不理解
optmize
中的
fvalue
部分。如果这就是我要找的,为什么我要给函数提供这些信息?这会是最初的猜测吗?另外,t0是已知的,但我在代码中更改了它,并且
z
fvalue
是数据您已经观察到并且正在进行拟合的点。因此,假设您的
f
格式正确,
fvalues
对应于
f(z)
加上一些噪音。这与代码中的
zlevels
pottemp
相对应,但我当时对此有点困惑,因为您没有在文本中指定。我已更新了命名以匹配您的问题。哦,太好了!这就是我需要的。谢谢
import numpy as np
import scipy.optimize

def f(zlevels, t0, a1, a2, a3, z1, z2, H):
    """
    Function to evaluate f, given a set of variables
    """
    # Check that no samples are out of bounds
    if any(zlevels < 0) or any(zlevels > H):
        quit("Values of zlevels out of bounds")

    pottemp = np.zeros(zlevels.shape)
    mask1 = zlevels <= z1
    mask2 = (z1 < zlevels) & (zlevels <= z2)
    mask3 = z2 < zlevels

    z1_arr1 = np.ones(sum(mask2))*z1
    z1_arr2 = np.ones(sum(mask3))*z1
    z2_arr = np.ones(sum(mask3))*z2

    pottemp[mask1] = zlevels[mask1] * a1 + t0
    pottemp[mask2] = z1_arr1 * a1 + t0 + a2 * (zlevels[mask2] - z1)
    pottemp[mask3] = z1_arr2 * a1 + t0 + a2 * (z2_arr - z1) + a3 * (zlevels[mask3] - z2)

    return pottemp

def obj_fun(x, zlevels, pottemp, t0, H):
    """
    Least-squares objective function for the problem
    """
    a1, a2, a3, z1, z2 = x
    # Swap order if z1 is larger than z2
    if z1 > z2:
        z1, z2 = z2, z1

    pottemp_pred = f(zlevels, t0, a1, a2, a3, z1, z2, H)
    return sum((pottemp_pred-pottemp)**2) 

def optimize(zlevels, pottemp, t0, H):
    """
    Optimize a1, a2, a3, z1, z2
    """

    starting_guess = [0,0,0,0.5,2.5]
    res = scipy.optimize.minimize(obj_fun, starting_guess, args=(zlevels, pottemp, t0, H), \
            bounds=[(None,None),(None,None),(None,None),(0,H),(0,H)])
    x = res.x
    # Swap order if z1 is larger than z2
    if x[-2] > x[-1]:
        x[-2], x[-1] = x[-1], x[-2]
    return x

# Make the true model for testing
t0 = 0.5
a1 = -1
a2 = +1
a3 = -2
z1 = 1
z2 = 2
H = 3

# Generate some variables
n = 1000
zlevels = np.random.random(n)*3
# Get values and add some random noise
pottemp = f(zlevels, t0, a1, a2, a3, z1, z2, H) + np.random.normal(0,0.1, size=n)

print("Correct values:", a1, a2, a3, z1, z2)
a1, a2, a3, z1, z2 = optimize(zlevels, pottemp, t0, H)
print("Fitted values:", a1, a2, a3, z1, z2)