Python 西皮元';t找到最佳值(简单余弦函数)

Python 西皮元';t找到最佳值(简单余弦函数),python,optimization,scipy,Python,Optimization,Scipy,我试图使用scipy优化器估计余弦函数的参数(是的,我知道可以使用arc cos,但我不想这样做) 代码+演示: import numpy import scipy def solver(data): Z=numpy.zeros(len(data)) a=0.003 for i in range(len(data)): def minimizer(b): return numpy.abs(data[i]-numpy.cos(b))

我试图使用scipy优化器估计余弦函数的参数(是的,我知道可以使用arc cos,但我不想这样做)

代码+演示:

import numpy
import scipy

def solver(data):
    Z=numpy.zeros(len(data))
    a=0.003
    for i in range(len(data)):
        def minimizer(b):
            return numpy.abs(data[i]-numpy.cos(b))
        Z[i]=scipy.optimize.minimize(minimizer,a,bounds=[(0,numpy.pi)],method="L-BFGS-B").x[0]
    return Z

Y=numpy.zeros(100)
for i in range(100):
   Y[i]=numpy.cos(i/25)

solver(Y)
结果不是很好,当cos函数的参数达到2以上的值时,估计值“跳过”这些值并返回最大参数值

array([0.        , 0.04      , 0.08      , 0.12      , 0.16      ,
       0.2       , 0.24      , 0.28      , 0.32      , 0.36      ,
       0.4       , 0.44      , 0.48      , 0.52      , 0.56      ,
       0.6       , 0.64      , 0.67999999, 0.72      , 0.75999999,
       0.8       , 0.83999999, 0.88      , 0.92      , 0.95999999,
       1.        , 1.04      , 1.08      , 1.12      , 1.16      ,
       1.2       , 1.24      , 1.28      , 1.32      , 1.36      ,
       1.4       , 1.44      , 1.48      , 1.52      , 1.56      ,
       1.6       , 1.64      , 1.68      , 1.72      , 1.76      ,
       1.8       , 1.84      , 1.88      , 1.91999999, 1.95999999,
       2.        , 2.04      , 3.14159265, 3.14159265, 3.14159265,
       3.14159265, 3.14159265, 3.14159265, 3.14159265, 3.14159265,...

是什么导致了这种现象?是否有其他一些优化器/设置可以帮助解决此问题

原因是,对于函数(例如)
f=abs(cos(0.75*pi)-cos(z))
梯度
f'
恰好在
z=pi
处消失,如下图所示:

如果您在优化过程中检查结果,您将看到:

      fun: array([0.29289322])
 hess_inv: <1x1 LbfgsInvHessProduct with dtype=float64>
      jac: array([0.])
  message: b'CONVERGENCE: NORM_OF_PROJECTED_GRADIENT_<=_PGTOL'
     nfev: 16
      nit: 2
   status: 0
  success: True
        x: array([3.14159265])
哪些产出:

Step #1: xk = [0.006]
Step #2: xk = [3.14159265]
因此,在第二步中,它击中了
z>=pi
,这被投射回
z=pi

您可以通过将边界减少到例如
bounds=[(0,0.99*np.pi)]
来避免这个问题。这将为您提供预期的结果,但是该方法不会收敛;您将看到如下内容:

      fun: array([1.32930966e-09])
 hess_inv: <1x1 LbfgsInvHessProduct with dtype=float64>
      jac: array([0.44124484])
  message: b'ABNORMAL_TERMINATION_IN_LNSRCH'
     nfev: 160
      nit: 6
   status: 2
  success: False
        x: array([2.35619449])

除了一般的
minimize
方法外,SciPy还有
minimize\u scalar
专门用于一维问题,以及
least\u squares
用于最小化测量两个量之间差异的特定类型的函数(例如
cos(b)
diff[i]
此处)。后者在这里表现良好,即使没有微调

for i in range(len(data)):
    Z[i] = scipy.optimize.least_squares(lambda b: data[i] - numpy.cos(b), a, bounds=(0, numpy.pi)).x[0]
传递给
最小二乘法的函数是我们希望接近0的函数,没有绝对值。我要补充的是,a=0.003似乎是起点的次优选择,因为它离边界太近了;尽管如此,它还是有效的

另外,正如已经发布的
a_guest
一样,标量根查找方法应该做同样的事情,同时在这里抛出更少的惊喜,因为我们已经有了一个很好的括号间隔[0,pi]。二分法可靠但速度慢;这是我可能会用到的

for i in range(len(data)):
    Z[i] = scipy.optimize.brentq(lambda b: data[i] - numpy.cos(b), 0, numpy.pi)

可能不是你想要的答案,但是用
val%=2*numpy.pi
对你的输入进行预处理可能会奏效。@Dole除此之外,代码是不可运行的-我希望其他人比我更了解你想要实现什么,以及你的策略是什么。@T先生,对不起,数组未初始化。我想有一个优化器,可以找到余弦参数。因此,如果它被输入cos(2.4),它应该返回2.4。相反,正如可以看到的,它返回3.14…@Dole不知道为什么它不工作,但这绝对是一个工作。您想要找到的是函数
data[i]-np.cos(b)
的根。我尝试了对分方法。然而,它抱怨说,尽管这些标志有所不同,但它们并没有什么不同,有没有黑客?最小二乘法工作得很好,但所有的公差都需要最大化,否则误差会迅速增长。@Dole如果它抱怨类似的符号,那可能是因为它们确实是相同的。你能提供
f
的定义以及它不适用的情况吗?最好同时三次检查对
bisect
的调用。确切的错误消息是什么?
for i in range(len(data)):
    Z[i] = scipy.optimize.least_squares(lambda b: data[i] - numpy.cos(b), a, bounds=(0, numpy.pi)).x[0]
for i in range(len(data)):
    Z[i] = scipy.optimize.brentq(lambda b: data[i] - numpy.cos(b), 0, numpy.pi)