首页 > 解决方案 > 如何使用python在短时间内获得具有两个变量积分表达式的成本函数的最小值?

问题描述

我想找到成本函数 T的最小值。成本函数T具有两个变量(Q 和 r)的表达式。我还需要找到成本函数T达到全局最小值的Q 和 r值。(如果有多个全局最小值 - 那么全部) Q 和 r 的界限是:0 < Q < 15000 ;0 < r < 5000 这里是方程

在此处输入图像描述

我正在使用Sympy 库来生成方程。并使用scipy.optimize.minimize的最小化函数 来找到最小值。函数的代码是:

from sympy import *
from scipy.optimize import root_scalar
mean, std = 291, 253
l = 7 #
m = 30
#Q = mean*(lead_time + shelf_life)
p = 5
w = 2
K = 100
c = 5
h = 0.001 #per unit per  day
x = symbols("x")
t = symbols("t")
r = symbols("r")
Q = symbols("Q")
#defining Cumulative distribution function
def cdf():
  cdf_eqn = (1/(std*sqrt(2*pi)))*exp(-(((t-mean)**2)/(2*std**2)))
  cdf = Integral(cdf_eqn, (t,-oo,x)).doit()
  return cdf
#defining Probability density function
def pdf():
  pdf = (1/(std*sqrt(2*pi)))*exp(-((( (x - mean)**2)/(2*std**2)))).doit()
  return pdf
pdf = pdf()
cdf = cdf()
#getting the equation in place
G = K + c*Q + w*(Integral(cdf , (x, 0, Q)) + Integral(cdf.subs(x, (r + Q - x))*cdf , (x, 0, r)))\
     + p*(mean*l - r + Integral(cdf , (x, 0, r)))
CL = (Q - r + mean*l - Integral(cdf , (x, 0, Q)) - Integral(cdf.subs(x, (r + Q - x))*cdf , (x, 0, r)) + Integral(cdf , (x, 0, r)))/mean  
I = h*(Q + r - mean*l - Integral(cdf , (x, 0, Q)) - Integral(cdf.subs(x, (r + Q - x))*cdf , (x, 0, r)) + Integral(cdf , (x, 0, r)))/2
#TC.free_symbols
#optimising the cost function
from  scipy import optimize
def f(params):
    r, Q = params 
    TC = G/CL + I
    return TC
initial_guess = [2500., 10000.]
result = optimize.minimize(f, initial_guess, tol=1e-6 )
if result.success:
    fitted_params = result.x
    print(fitted_params)
else:
    raise ValueError(result.message)

但它会引发如下错误。

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
/usr/local/lib/python3.6/dist-packages/scipy/optimize/optimize.py in _approx_fprime_helper(xk, f, epsilon, args, f0)
    699             try:
--> 700                 df = df.item()
    701             except (ValueError, AttributeError):
AttributeError: 'Zero' object has no attribute 'item'
During handling of the above exception, another exception occurred:
ValueError                                Traceback (most recent call last)
5 frames
<ipython-input-6-e9bb4190fef5> in <module>()
     39     return TC
     40 initial_guess = [2500., 10000.]
---> 41 result = optimize.minimize(f, initial_guess, tol=1e-6 )
     42 if result.success:
     43     fitted_params = result.x
/usr/local/lib/python3.6/dist-packages/scipy/optimize/_minimize.py in minimize(fun, x0, args, method, jac, hess, hessp, bounds, constraints, tol, callback, options)
    602         return _minimize_cg(fun, x0, args, jac, callback, **options)
    603     elif meth == 'bfgs':
--> 604         return _minimize_bfgs(fun, x0, args, jac, callback, **options)
    605     elif meth == 'newton-cg':
    606         return _minimize_newtoncg(fun, x0, args, jac, hess, hessp, callback,
/usr/local/lib/python3.6/dist-packages/scipy/optimize/optimize.py in _minimize_bfgs(fun, x0, args, jac, callback, gtol, norm, eps, maxiter, disp, return_all, **unknown_options)
   1007     else:
   1008         grad_calls, myfprime = wrap_function(fprime, args)
-> 1009     gfk = myfprime(x0)
   1010     k = 0
   1011     N = len(x0)
/usr/local/lib/python3.6/dist-packages/scipy/optimize/optimize.py in function_wrapper(*wrapper_args)
    325     def function_wrapper(*wrapper_args):
    326         ncalls[0] += 1
--> 327         return function(*(wrapper_args + args))
    328 
    329     return ncalls, function_wrapper
/usr/local/lib/python3.6/dist-packages/scipy/optimize/optimize.py in approx_fprime(xk, f, epsilon, *args)
    763 
    764     """
--> 765     return _approx_fprime_helper(xk, f, epsilon, args=args)
    766 
    767 
/usr/local/lib/python3.6/dist-packages/scipy/optimize/optimize.py in _approx_fprime_helper(xk, f, epsilon, args, f0)
    700                 df = df.item()
    701             except (ValueError, AttributeError):
--> 702                 raise ValueError("The user-provided "
    703                                  "objective function must "
    704                                  "return a scalar value.")
ValueError: The user-provided objective function must return a scalar value.

此外,使用其他方法,运行时间较长,超过 30 分钟左右,最终抛出错误。如何在很短的时间内找到全局最小值以及 Q 和 r 的值。最好1-5分钟左右。

代表我的朋友发帖

标签: pythonnumpyscipyintegrationsympy

解决方案


只是对未来的说明:在你的 functionf中,如果你设置了一些r东西Q,它不会改变你之后使用的 SymPy 表达式,因为它们之前已经为符号变量定义了。

您的工作看起来很数字化,实际上,由于您的答案不需要符号,因此您最好进行非符号积分。SymPy 是纯 Python,尤其是在集成方面可能会很慢,而 SciPy 的设计速度很快。这就是我将所有内容都转换为 SciPy 的原因:

编辑:我知道我对r=0收敛的第一个答案是可疑的。在@VishalAnand 对从 开始的 cdf 积分进行更正后-inf,我尝试再次运行该程序。T 的单次迭代大约需要 15 秒,但没有找到解决方案;可能是由于现在存在一个非常复杂的表面。

cdf 也产生了错误的值;例如,quad(pdf, -np.inf, 50000)[0]产生了一个非常接近 0 的数字,而它应该接近 1。这破坏了最小化,所以我尝试了类似quad(pdf, -1000000, 50000)[0]的方法,结果产生了相似的值sympy.N(sympy.erf((x-mean)/(sqrt(2)*std)))/2 + 1/2,结果证明计算速度更快。

问题是 SciPy 最小化函数不能收敛,而是产生了ABNORMAL_TERMINATION_IN_LNSRCH。所以我给了它一个特定的使用方法:Nelder-Mead。这收敛了。inf但最终值非常令人担忧,因为它们在和之间跳跃-1.793193606659277e+19。Python 不知道溢出错误(至少据我所知),所以我能想到的唯一可能的解释是函数 C 的根导致 T 在 r 和 Q 的某些值处具有渐近线。

这远远超出了我的范围,所以我将在这里留下我的最新努力:

from numpy import sqrt, pi, exp, inf
from sympy import erf, N
from scipy import optimize
from scipy.integrate import quad

mean, std = 291, 253
l = 7
m = 30
# Q = mean*(lead_time + shelf_life)
p = 5
w = 2
K = 100
c = 5
h = 0.001  # per unit per  day


# defining Probability density function
def pdf(x):
    return (1 / (std * sqrt(2 * pi))) * exp(-(((x - mean) ** 2) / (2 * std ** 2)))


# defining Cumulative distribution function
def cdf(x):
    # cdf1 = quad(pdf, -1000000, x)[0]  # slow
    # cdf2 = quad(pdf, -inf, x)[0]  # slow and produces wrong values at hugh positive x
    cdf3 = N(erf((x-mean)/(sqrt(2)*std)))/2 + 1/2
    return cdf3


# getting the equation in place
def G(r, Q):
    return K + c * Q \
           + w * (quad(cdf, 0, Q)[0] + quad(lambda x: cdf(r + Q - x) * cdf(x), 0, r)[0]) \
           + p * (mean * l - r + quad(cdf, 0, r)[0])


def CL(r, Q):
    return (Q - r + mean * l - quad(cdf, 0, Q)[0]
            - quad(lambda x: cdf(r + Q - x) * cdf(x), 0, r)[0]
            + quad(cdf, 0, r)[0]) / mean


def I(r, Q):
    return h * (Q + r - mean * l - quad(cdf, 0, Q)[0]
                - quad(lambda x: cdf(r + Q - x) * cdf(x), 0, r)[0]
                + quad(cdf, 0, r)[0]) / 2


def f(params):
    r, Q = params
    TC = G(r, Q)/CL(r, Q) + I(r, Q)
    return TC


initial_guess = [2343.70601496,  239.89137499]
result = optimize.minimize(f, initial_guess, bounds=[(0, 5000), (0, 15000)], method="Nelder-Mead")
# result = f(initial_guess)  # single check
print(result)


在约 15 秒内产生以下输出:

 final_simplex: (array([[2343.70594323,  257.01581672],
       [2343.70594323,  257.01581672],
       [2343.70594323,  257.01581672]]), array([-1.79319361e+19, -1.79319361e+19, -1.79319361e+19]))
           fun: -1.793193606659277e+19
       message: 'Optimization terminated successfully.'
          nfev: 360
           nit: 155
        status: 0
       success: True
             x: array([2343.70594323,  257.01581672])

希望有资格的人能解释一下。对于我自己的任何不便或错误结论,我们深表歉意。


推荐阅读