minimizing a function with an array input - python

I want to use scipy.optimize.minimize on a function with an array type variable input. This is what I hope to do.
I have the following signal,
import numpy as np
time = np.linspace(0, 1, 501)
data = np.cos(2 * np.pi * 4 * time) + np.cos(2 * np.pi * 9 * time) + np.cos(2 * np.pi * 20 * time)
noise = np.sqrt(1 / 25) * np.random.randn(501)
signal = data + noise
and I am hoping to find a curve fit for this signal. Since I created the data myself, I know that a sum of cosine functions will work for this. So the function that I hope to optimize is the following:
def cos_sum(x, P):
assert isinstance(P, np.ndarray)
assert P.shape[0] == P.shape[1]
sums = []
for param in P:
a, b, c = param
sums.append(a * np.cos(b * (x - c)))
sums = np.array(sums)
return np.sum(sums, axis=0)
In order to use minimize to find the correct parameters, I create this residual function.
def resid(params, x):
assert isinstance(params, np.ndarray)
fit = cos_sum(x, params)
residual = np.sqrt(np.mean(np.abs(fit - signal)) ** 2)
return residual
I now need to create a guess. Since I already know how the signal was created, I made the following guess:
guess_A = np.random.normal(1, .2, size=3)
guess_B = 2 * np.pi * np.array([4, 9, 20], dtype=float)
guess_C = np.random.normal(0, .2, size=3)
guess = np.array([guess_A, guess_B, guess_C]).T
However, I am unable to run the following:
from scipy.optimize import minimize
optimization = minimize(resid, guess, args=(time))
and I receive the following error:
Traceback (most recent call last):
File "/Users/nickeisenberg/GitRepos/Python_Misc/Misc/minimize_curvefit_vector_variables.py", line 70, in <module>
optimization = minimize(resid, guess, args=(time))
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/scipy/optimize/_minimize.py", line 676, in minimize
res = _minimize_bfgs(fun, x0, args, jac, callback, **options)
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/scipy/optimize/_optimize.py", line 1296, in _minimize_bfgs
sf = _prepare_scalar_function(fun, x0, jac, args=args, epsilon=eps,
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/scipy/optimize/_optimize.py", line 263, in _prepare_scalar_function
sf = ScalarFunction(fun, x0, args, grad, hess,
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/scipy/optimize/_differentiable_functions.py", line 158, in __init__
self._update_fun()
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/scipy/optimize/_differentiable_functions.py", line 251, in _update_fun
self._update_fun_impl()
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/scipy/optimize/_differentiable_functions.py", line 155, in update_fun
self.f = fun_wrapped(self.x)
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/scipy/optimize/_differentiable_functions.py", line 137, in fun_wrapped
fx = fun(np.copy(x), *args)
File "/Users/nickeisenberg/GitRepos/Python_Misc/Misc/minimize_curvefit_vector_variables.py", line 53, in resid
fit = cos_sum(x, params)
File "/Users/nickeisenberg/GitRepos/Python_Misc/Misc/minimize_curvefit_vector_variables.py", line 30, in cos_sum
assert P.shape[0] == P.shape[1]
IndexError: tuple index out of range
Is this possible to do?

The problem is that minimize treats parameters as 1D array. Adding print just before failing assert shows, that it reshaped guess array to 1D array.
Changing cos_sum so that it accepts 1D array of params fixes this problem. Here is the code.
def cos_sum(x, P):
assert isinstance(P, np.ndarray)
sums = []
for i in range(0, P.shape[0], 3):
a, b, c = P[i], P[i+1], P[i+2]
sums.append(a * np.cos(b * (x - c)))
sums = np.array(sums)
return np.sum(sums, axis=0)
Result:
optimization = minimize(resid, guess, args=(time))
print(optimization.x)
[ 0.96805816 25.1679919 0.25020317 1.00261543 56.44511497
0.77872223 1.00966167 125.71622787 0.55004217]
plt.figure(figsize=(8, 4))
plt.plot(data)
plt.plot([cos_sum(t, optimization.x) for t in time], 'C1--')
plt.show()

Related

Error, trying to plot a graph of solution to a Second Order ODE using Euler Method

I am doing a project, where I want to use Euler's Method to show a solution to this Second Order Different equation
0=y''+y'+9.81y
So I started by changing the second-order into a system of first-order equations
y'=u, u'=f(t,y,u)
With initial condition
y(0)=180, u(0)=0
So I get two equation in the end
y[n + 1] = y[n] + u[n] * (t[n + 1] - t[n]), u[n + 1] = u[n] + f(u[0], y[n], t[0]) * (t[n + 1] - t[n])
This is my code
import numpy as np
import matplotlib.pyplot as plt
def odeEuler(f, y0, u0, t):
y = np.zeros(len(t))
u = np.zeros(len(t))
y[0] = y0
u[0] = u0
for n in range(0, len(t) - 1):
y[n + 1] = y[n] + u[n] * (t[n + 1] - t[n])
u[n + 1] = u[n] + f(u[0], y[n], t[0]) * (t[n + 1] - t[n])
return y, u
t = np.linspace(0, 100)
y0 = 180
u0 = 0
f = lambda u, y, t: -9.81 * y - u
y = odeEuler(f, y0, u0, t)
plt.plot(t, y, 'b.-')
plt.legend(['Euler'])
plt.axis([0, 100, 0, 200])
plt.grid(True)
plt.show()
However, when I run the code, it give me the error
Traceback (most recent call last):
File "/Users/huangy15/PycharmProjects/Draft/Damped Driven Pendulum/Praying this works.py", line 22, in <module>
plt.plot(t, y, 'b.-')
File "/Users/huangy15/PycharmProjects/Draft/Damped Driven Pendulum/venv/lib/python3.7/site-packages/matplotlib/pyplot.py", line 3021, in plot
**({"data": data} if data is not None else {}), **kwargs)
File "/Users/huangy15/PycharmProjects/Draft/Damped Driven Pendulum/venv/lib/python3.7/site-packages/matplotlib/axes/_axes.py", line 1605, in plot
lines = [*self._get_lines(*args, data=data, **kwargs)]
File "/Users/huangy15/PycharmProjects/Draft/Damped Driven Pendulum/venv/lib/python3.7/site-packages/matplotlib/axes/_base.py", line 315, in __call__
yield from self._plot_args(this, kwargs)
File "/Users/huangy15/PycharmProjects/Draft/Damped Driven Pendulum/venv/lib/python3.7/site-packages/matplotlib/axes/_base.py", line 501, in _plot_args
raise ValueError(f"x and y must have same first dimension, but "
ValueError: x and y must have same first dimension, but have shapes (50,) and (2, 50)
Can anyone help me check if my idea works, and if not, what other approaches I can take? Thanks!
Your odeEuler function is returning two variables: y and u, you need to select just one of them to plot.
Store the output of the function in two different variables will solve the problem:
y, u = odeEuler(f, y0, u0, t)

Python Scipy : "TypeError: fsolve: there is a mismatch between the input and output shape of the 'func' argument"

I have the following system of 2 matricial equations where a and b are unknown vectors with for each 7 components. D, D1, D2, P1, P2, F1, F2 are matrices (7x7).
# define the equations
def f(x):
a = np.zeros(7)
b = np.zeros(7)
for i in range(7):
a[i] = x[i]
b[i] = x[7+i]
# Looking for an endomorphism that has D eigen values
D = a**2*D1 + b**2*D2
eq1 = np.dot(P1.T*a**2,P1) + np.dot(P1.T*a,b*P2) + np.dot(P2.T*b,a*P1) + np.dot(P2.T*b**2,P2) - np.eye(7)
eq2 = np.dot(F1,a*P1) + np.dot(F1,b*P2) + np.dot(F2,a*P1) + np.dot(F2,b*P2) - np.dot(a*P1 + b*P2,D)
return np.array([eq1,eq2])
# inital guess
x0 = np.ones(14)
print('x0 = ', x0)
# solving
x = fsolve(f, x0)
print(x)
Unfortunately, at the execution, I get :
Traceback (most recent call last):
File "compute_solving_Matricial_Equations_with_vectors_a_and_b_unknown.py", line 110, in <module>
x = fsolve(f, x0)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/scipy/optimize/minpack.py", line 139, in fsolve
res = _root_hybr(func, x0, args, jac=fprime, **options)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/scipy/optimize/minpack.py", line 196, in _root_hybr
shape, dtype = _check_func('fsolve', 'func', func, x0, args, n, (n,))
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/scipy/optimize/minpack.py", line 32, in _check_func
raise TypeError(msg)
TypeError: fsolve: there is a mismatch between the input and output shape of the 'func' argument 'f'.
I tried previously by doing at the end of f function :
return np.array([eq1,eq2].ravel()
instead of return np.array([eq1,eq2].
But I get the same error. What might be wrong here?
I am handling with (7x7) matrices in my 2 equations but I have only 14 unknown (7 components for vector a and 7 for vector b).
Update 1
Following the advice of #Warren Weckesser, I did to check:
# define the equations
def f(x):
a = np.zeros(7)
b = np.zeros(7)
for i in range(7):
a[i] = x[i]
b[i] = x[7+i]
# Looking for an endomorphism that has D eigen values
#D = D1 + D2
D = a**2*D1 + b**2*D2
eq1 = np.dot(P1.T*a**2,P1) + np.dot(P1.T*a,b*P2) + np.dot(P2.T*b,a*P1) + np.dot(P2.T*b**2,P2) - np.eye(7)
eq2 = np.dot(F1,a*P1) + np.dot(F1,b*P2) + np.dot(F2,a*P1) + np.dot(F2,b*P2) - np.dot(a*P1 + b*P2,D)
print(' shape(a) = ', np.shape(a))
print(' shape(b) = ', np.shape(b))
#return np.array([eq1,eq2]).ravel()
return np.concatenate((eq1, eq2))
and get as output :
Traceback (most recent call last):
File "compute_solving_Matricial_Equations_with_vectors_a_and_b_unknown_FOR_STACKOVER.py", line 89, in <module>
shape(a) = (7,)
shape(b) = (7,)
x = fsolve(f, x0)
File "/opt/intel/intelpython3/lib/python3.7/site-packages/scipy/optimize/minpack.py", line 147, in fsolve
res = _root_hybr(func, x0, args, jac=fprime, **options)
File "/opt/intel/intelpython3/lib/python3.7/site-packages/scipy/optimize/minpack.py", line 213, in _root_hybr
shape, dtype = _check_func('fsolve', 'func', func, x0, args, n, (n,))
File "/opt/intel/intelpython3/lib/python3.7/site-packages/scipy/optimize/minpack.py", line 40, in _check_func
raise TypeError(msg)
TypeError: fsolve: there is a mismatch between the input and output shape of the 'func' argument 'f'.Shape should be (14,) but it is (14, 7).
As you can see, it shows one time the print of shape(a) and shape(b) before failing.

python fsolve: 'list' object is not callable

I seem to be having a problem with scipy.optimize.fsolve(). The error message is:
TypeError: 'list' object is not callable.
Code:
def eqs(P, z1):
x1 = z1[0]
y1 = z1[1]
x2 = 1 - x1
y2 = 1 - y1
fl1 = Fug(0, fsolve(PR(x1, P), 0.5), x1, P)
fl2 = Fug(1, fsolve(PR(x1, P), 0.5), x2, P)
fg1 = Fug(0, fsolve(PR(y1, P), 150), y1, P)
fg2 = Fug(1, fsolve(PR(y1, P), 150), y2, P)
error = (x1*fl1 - y1*fg1) + ((1-x1)*fl2 - (1-y1)*fg2)
phiphi = x1*fl1 - y1*fg1
return [phiphi, error]
def main():
P = 18
x1 = (19.99 - P) / (19.99 - 3.59)
y1 = IdealCase_y1(x1)
z1 = [x1, y1]
soln = fsolve(eqs(P, z1), z1)
x1, y1 = soln
return soln
I have used lists(The one with []'s) in fsolve before without a problem, so I'm unsure as to where to look for the problem.
The functions eqs(P, z1), and thus Fug(...), as well as IdealCase_y1 run without a problem, however when running main(), python returns the above mentioned error. The idea is to create a function main() which I can input different P values and return x1, y1 as output. the x1 = ... in main is an "informed guess", to tell fsolve where to look, and a y1 guess is then generated from that value.
edit: IdealCase_y1(x1) is a function used to estimate the value of y1 required by fsolve. The traceback is:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Python27\lib\site-packages\spyderlib\widgets\externalshell\sitecustomize.py", line 540, in runfile
execfile(filename, namespace)
File "C:/Users/ShahuN/Documents/Project/q2_v0.3.py", line 229, in <module>
test = main()
File "C:/Users/ShahuN/Documents/Project/q2_v0.3.py", line 223, in main
soln = fsolve(eqs(P, z1), [x1, y1])
File "C:\Python27\lib\site-packages\scipy\optimize\minpack.py", line 140, in fsolve
res = _root_hybr(func, x0, args, jac=fprime, **options)
File "C:\Python27\lib\site-packages\scipy\optimize\minpack.py", line 197, in _root_hybr
shape, dtype = _check_func('fsolve', 'func', func, x0, args, n, (n,))
File "C:\Python27\lib\site-packages\scipy\optimize\minpack.py", line 20, in _check_func
res = atleast_1d(thefunc(*((x0[:numinputs],) + args)))
TypeError: 'list' object is not callable
if that's what is meant by the traceback.
soln = fsolve(eqs(P, z1), z1)
1)
func should be a callable function.
2)
the expected argument (optional) is tuple not list, you have to convert your list to tuple when you invoke fsolve()
scipy.optimize.fsolve(func, x0, args=(), fprime=None, full_output=0, col_deriv=0, xtol=1.49012e-08, maxfev=0, band=None, epsfcn=None, factor=100, diag=None)[source]
func : callable f(x, *args)
A function that takes at least one (possibly vector) argument.
args : tuple, optional
Any extra arguments to func.
Edit:
You invoke your function eqs in a wrong way, it should look like this:
soln = fsolve(eqs, P, args=(z1))
x1, y1 = soln

Minimizing three variables in python using scipy

I need help on minimizing function in python using three variable constraints.
I have posted the code which is giving me error. If you would like I can post the entire code to to show the mathematical calculation.:
# the time-series data.
coeff = [0.2, 0.3, 0.4]
x =[146, 96, 59, 133, 192, 127, 79, 186, 272, 155, 98, 219]
test = y(x,coeff)
print("x : ", x)
print("y : ",test)
result = minimize(mape, coeff, (x,), bounds =[(0,1),(0,1), (0,1)], method='SLSQP')
opt = result.x
print("opt : ", result.x)
This is my code:
from __future__ import division
import numpy as np
from scipy.optimize import minimize
#coeffList[0] = alpha
#coeffList[1] = beta
#coeffList[2] =gamma
def mape(x, coeffList):
diff = abs(y(x,coeffList)-x)
print("np.mean(diff/x) : ", np.mean(diff/x))
return np.mean(diff/x)
#Holt Winters-Multiplicative
def y(x, coeffList , debug=True):
c =4
#Compute initial b and intercept using the first two complete c periods.
xlen =len(x)
print("xlen : ", xlen)
#if xlen % c !=0:
# return None
fc =float(c)
xbar2 =sum([x[i] for i in range(c, 2 * c)])/ fc
print("xbar2 : ",xbar2)
xbar1 =sum([x[i] for i in range(c)]) / fc
print("xbar1 : ", xbar1)
b0 =(xbar2 - xbar1) / fc
if debug: print ("b0 = ", b0)
#Compute for the level estimate a0 using b0 above.
tbar =sum(i for i in range(1, c+1)) / fc
print("tbar : ",tbar)
a0 =xbar1 - b0 * tbar
if debug: print ("a0 = ", a0)
#Compute for initial indices - seasonality
I =[x[i] / (a0 + (i+1) * b0) for i in range(0, xlen)]
if debug: print ("Initial indices = ", I)
S=[0] * (xlen+ c)
for i in range(c):
S[i] =(I[i] + I[i+c]) / 2.0
print ("S[",i,"]=", S[i])
#Normalize so S[i] for i in [0, c) will add to c.
tS =c / sum([S[i] for i in range(c)])
print("tS : ", tS)
for i in range(c):
S[i] *=tS
if debug: print ("Normalized S[",i,"]=", S[i])
# Holt - winters proper ...
if debug: print( "Use Holt Winters formulae")
At =a0
Bt =b0
#y =[0] * (xlen)
y = np.empty(len(x),float)
for i in range(xlen):
Atm1 =At
Btm1 =Bt
At =coeffList[0] * x[i] / S[i] + (1.0-coeffList[0]) * (Atm1 + Btm1)
Bt =coeffList[1] * (At - Atm1) + (1- coeffList[1]) * Btm1
S[i+c] =coeffList[2] * x[i] / At + (1.0 - coeffList[2]) * S[i]
y[i]=(a0 + b0 * (i+1)) * S[i]
#print ("i=", i+1, "y=", y[i], "S=", S[i], "(level)Atm1=", Atm1, "(trend)Btm1=",Btm1, "(level)At=", At, "Bt=", Bt, "S[i+c]=", S[i+c], "y[i]=", y[i])
print ("i=", i+1, "y=", y[i], "S=", S[i], "(level)At=", At, "Bt=", Bt, "y[i]=", y[i])
#coeffList[0] = alpha
#coeffList[1] = beta
#coeffList[2] =gamma
return y
#print (i,y[i], F[i])
#Forecast for next c periods:
#for m in range(c):
#print( "forecast:", (At + Bt* (m+1))* S[ylen + m])
# the time-series data.
coeff = [0.2, 0.3, 0.4]
x =[146, 96, 59, 133, 192, 127, 79, 186, 272, 155, 98, 219]
bnds = ((0,1), (0,1), (0,1))
coeff = [0.2, 0.3, 0.4]
test = y(x,coeff)
print("x : ", x)
print("y : ",test)
#cons = ({'type' :'alpha', 'fun' :lambda x: np.array(x[0]<=1 and x[0]>=0)})
result = minimize(mape, coeff, (x,), method ="L-BFGS-B", bounds =bnds)
opt = result.x(0)
print("opt : ", result.x)
This is the error message. The function without minimization function works just fine.
Traceback (most recent call last):
File "C:\Users\gelalmp\Desktop\Bibha Gelal_SD\testing_Optimization_HWM.py", line 100, in <module>
result = minimize(mape, coeff, (x,), method ="L-BFGS-B", bounds =bnds)
File "C:\Python27\lib\site-packages\scipy\optimize\_minimize.py", line 380, in minimize
callback=callback, **options)
File "C:\Python27\lib\site-packages\scipy\optimize\lbfgsb.py", line 314, in _minimize_lbfgsb
f, g = func_and_grad(x)
File "C:\Python27\lib\site-packages\scipy\optimize\lbfgsb.py", line 258, in func_and_grad
f = fun(x, *args)
File "C:\Users\gelalmp\Desktop\Bibha Gelal_SD\testing_Optimization_HWM.py", line 12, in mape
diff = abs(y(x,coeffList)-x)
File "C:\Users\gelalmp\Desktop\Bibha Gelal_SD\testing_Optimization_HWM.py", line 30, in y
xbar2 =sum([x[i] for i in range(c, 2 * c)])/ fc
IndexError: index out of bounds
Change your last 4 lines to:
M=lambda p1, p2: mape(p2, p1)
result = minimize(M, coeff, (x,), method ="L-BFGS-B", bounds =bnds)
opt = result['x']
print("opt : ", result['x'])
And it should work now, need explanations? I get the optimization result ('opt : ', array([ 0.45330204, 0.26761714, 0. ]))
The lambda function reverses the order of how the parameters are supplied to mape. As you are attempting to find the coeff that minimize the mape() given a fixed x, the target function should take coeff first and x second, which is not the case for mape.
To your comment question: I thought you are using L-BFGS-B in your code. The difference are explained here: http://docs.scipy.org/doc/scipy/reference/tutorial/optimize.html#tutorial-sqlsp. I have to admit I don't too much detailed of SLSQP as that was long time ago in graduate school. BFGS is more common and every textbook explains it. L-BFGS-B supports bound constrained minimization. SLSQP supports bounds, as well as equality and inequality constraints. So, SLSQP can function when L-BFGS-B can't. See, http://scipy-lectures.github.io/advanced/mathematical_optimization/index.html?utm_source=twitterfeed&utm_medium=twitter.

ValueError: object too deep for desired array

""" ___ """
from scipy.optimize import root
import numpy as np
LENGTH = 3
def process(x):
return x[0, 0] + x[0, 1] * 5
def draw(process, length):
""" """
X = np.matrix(np.random.normal(0, 10, (length, 2)))
y = np.matrix([process(x) for x in X])
y += np.random.normal(3, 1, len(y))
return y.T, X.T
def maximum_likelyhood(y, X):
def objective(b):
return (X.T * (y - X * b.T))
x0 = np.matrix([0, 0])
res = root(objective, x0=x0)
return res.x
y, X = draw(process, LENGTH)
X = X.transpose()
b = np.matrix([[0], [1]])
print maximum_likelyhood(y, X)
produces a
Traceback (most recent call last):
File "ml.py", line 33, in <module>
maximum_likelyhood(y, X)
File "ml.py", line 26, in maximum_likelyhood
res = root(objective, x0=x0)
File "/usr/local/lib/python2.7/dist-packages/scipy/optimize/_root.py", line 168, in root
sol = _root_hybr(fun, x0, args=args, jac=jac, **options)
File "/usr/local/lib/python2.7/dist-packages/scipy/optimize/minpack.py", line 193, in _root_hybr
ml, mu, epsfcn, factor, diag)
ValueError: object too deep for desired array
I can't even gasp what the problem is is it in the b which goes into the objective
function? or is it in its output?
The problem is that fsolve and root do not accept matrixes as return value of the objective function.
For example this is a solution of above problem:
def maximum_likelyhood(y, X):
def objective(b):
b = np.matrix(b).T
return np.transpose(np.array((X.T * (y - X * b))))[0]
x0 = (1, 1)
res = root(objective, x0=x0)
return res.x

Categories