crbl
crbl

Reputation: 397

Minimize function with Scipy minimize

Trying to obtain the d value (integer) for which the Std_Diff objective function is minimal, using Scipy minimize.

My code:

def Std_Diff(d):
    return std(diff(df['BN'].values,d));

from scipy.optimize import minimize
b=(3,)
res = minimize(Std_Diff,(1,), method='SLSQP', bounds = b)

The **df['BN'].values** are 
Out[72]: 
array([ 2,  2,  2,  2,  3,  2,  7,  5,  7, 11,  8,  2, 11,  7, 15,  8,  7,
       12, 21, 19, 32, 35, 40, 35, 21, 19, 25, 20, 40, 80, 99], dtype=int64)

Error is

IndexError: too many indices for array

In case I do not use bounds:

res = minimize(Std_Diff,(1,), method='SLSQP')

I get another error:

> in _minimize_slsqp(func, x0, args, jac, bounds, constraints, maxiter,
> ftol, iprint, disp, eps, callback, **unknown_options)
>     368                 fx = float(np.asarray(func(x)))
>     369             except:
> --> 370                 raise ValueError("Objective function must return a scalar")
>     371             # Compute the constraints
>     372             if cons['eq']: ValueError: Objective function must return a scalar.

Upvotes: 3

Views: 1855

Answers (1)

hpaulj
hpaulj

Reputation: 231325

(I was stumbling around at the start, but I'll leave here so you can get some ideas of how to debug.)


You invoke minimize with:

Std_Diff,(1,)

that is the initial values is a scalar (or 1 number). minimize takes it's clue from that and sets the search variable to the same. That's the d it passes to your function, Std_Diff. But it also expects that function to return a single value as well. In other words, minimize a scalar function of a scalar value.

So std(diff(df['BN'].values,1)) should return a scalar. Evidently it does not.


OK, testing with the supposed values

In [115]: bf
Out[115]: 
array([ 2,  2,  2,  2,  3,  2,  7,  5,  7, 11,  8,  2, 11,  7, 15,  8,  7,
       12, 21, 19, 32, 35, 40, 35, 21, 19, 25, 20, 40, 80, 99], dtype=int64)
In [116]: np.std(np.diff(bf,1))
Out[116]: 9.9219733700285424

So my first guess is wrong.


Looking more carefully at the error stack, I see that the error occurs in your function, not after. It looks like a problem with the use of d.

/usr/local/lib/python3.5/dist-packages/numpy/lib/function_base.py in diff(a, n, axis)
   1913         raise ValueError(
-> 1914             "order must be non-negative but got " + repr(n))
   1915     a = asanyarray(a)

ValueError: order must be non-negative but got array([-64259548.28233695])

In the unbounded case, the search variable can go negative (very much so), raising an error in np.diff.

(the error you show is from During handling of the above exception, another exception occurred:. It's not the primary error, but a secondary one.)


The problem when specifying bounds, is that specification is incomplete. It requires a (min,max) tuple for each variable. So this works:

In [147]: minimize(Std_Diff,1, method='SLSQP', bounds=((3,None),))
...
Out[147]: 
     fun: 9.921973370028542
     jac: array([ 64259549.28233695])
 message: 'Positive directional derivative for linesearch'
    nfev: 3
     nit: 5
    njev: 1
  status: 8
 success: False
       x: array([ 1.])

Bounds for variables (only for L-BFGS-B, TNC and SLSQP). (min, max) pairs for each element in x, defining the bounds on that parameter. Use None for one of min or max when there is no bound in that direction.

Look at the error line:

--> 341         bnderr = bnds[:, 0] > bnds[:, 1]

it expects bnds to be a 2d array with 2 columns. For example:

In [153]: np.array(((3,10),))
Out[153]: array([[ 3, 10]])
In [154]: np.array((3,))
Out[154]: array([3])

I also modified the function to have a clearer idea of how its values changed

def Std_Diff(d):
    print(d)
    r = np.std(np.diff(bf,d))
    print(r)
    return r

Upvotes: 2

Related Questions