I want to use the function Hessiandiag from the package (Numdifftools) to get the diagonal elements of an Hessian matrix using the optimal parameters that minimizes a function.
Here's a simple example of the usage of Hessiandiag taken from developers website of Numdifftools:
import numpy as np
import numdifftools as nd
fun = lambda x : x[0] + x[1]**2 + x[2]**3
ddfun = lambda x : np.asarray((0, 2, 6*x[2]))
Hfun = nd.Hessdiag(fun)
hd = Hfun([1,2,3]) # HD = [ 0,2,18]
Say that my function that I want to get the Hessian matrix is too complex to be written using lambda. My function is stored in another file under the name Latent (using the def Latent(x1, x2, x3) command). I can't do the following:
from Latent import Latent # That's my function
import numpy as np
import numdifftools as nd
fun = lambda x1, x2, x3 : Latent(x1, x2, x3)
Hfun = nd.Hessdiag(fun)
hd = Hfun([np.array([1.2, 1.5, 2]), np.array(3.4, 5), 6]) # three parameters
...this doesn't work...
This is the error:
raise ValueError('%s must be scalar, one of [1 2 3 4].' % name)
ValueError: n must be scalar, one of [1 2 3 4].
How can I use nd.Hessdiag with my complex function without using lambda?
UPDATE
I have also tried this:
fun = lambda x: Latent(x[0], x[1], x[2])
Hfun = nd.Hessdiag(fun)
hd = Hfun([x1, x2, x3])
I get this error:
File "C:\Users\chamar.stu\AppData\Local\Continuum\Anaconda\lib\site-packages\spyderlib\widgets\externalshell\sitecustomize.py", line 601, in runfile
execfile(filename, namespace)
File "C:\Users\chamar.stu\AppData\Local\Continuum\Anaconda\lib\site-packages\spyderlib\widgets\externalshell\sitecustomize.py", line 66, in execfile
exec(compile(scripttext, filename, 'exec'), glob, loc)
File "F:/dropbox/Dropbox/Research/Fisher Martineau Sheng/SEC/codes/Python Latent Factor/V1/Main_v1.py", line 101, in <module>
hd = Hfun(np.array([est_param, allret_.T, n, capt, num_treat]))
File "C:\Users\chamar.stu\AppData\Local\Continuum\Anaconda\lib\site-packages\numdifftools\core.py", line 1161, in __call__
return self.hessdiag(x)
File "C:\Users\chamar.stu\AppData\Local\Continuum\Anaconda\lib\site-packages\numdifftools\core.py", line 1171, in hessdiag
dder, self.error_estimate, self.final_delta = self._partial_der(x)
File "C:\Users\chamar.stu\AppData\Local\Continuum\Anaconda\lib\site-packages\numdifftools\core.py", line 830, in _partial_der
self._x = np.asarray(x0, dtype=float)
File "C:\Users\chamar.stu\AppData\Local\Continuum\Anaconda\lib\site-packages\numpy\core\numeric.py", line 460, in asarray
return array(a, dtype, copy=False, order=order)
ValueError: setting an array element with a sequence.
Related
I recently ran into a question about integration and encountered a strange bug. I attempt a very simple problem using solve_ivp:
from scipy.integrate import solve_ivp
import numpy as np
def f(y, t):
return y
y0 = [1,1,1,1]
method = 'RK23'
s = solve_ivp(f, (0,1), y0, method=method, t_eval=np.linspace(0,1))
And it works fine. When I change to method='BDF' or method='Radau' I get an error:
Traceback (most recent call last):
File "<ipython-input-222-f11c4406e92c>", line 10, in <module>
s = solve_ivp(f, (0,1), y0, method=method, t_eval=np.linspace(0,1))
File "C:\ProgramData\Anaconda3\lib\site-packages\scipy\integrate\_ivp\ivp.py", line 455, in solve_ivp
solver = method(fun, t0, y0, tf, vectorized=vectorized, **options)
File "C:\ProgramData\Anaconda3\lib\site-packages\scipy\integrate\_ivp\radau.py", line 299, in __init__
self.jac, self.J = self._validate_jac(jac, jac_sparsity)
File "C:\ProgramData\Anaconda3\lib\site-packages\scipy\integrate\_ivp\radau.py", line 345, in _validate_jac
J = jac_wrapped(t0, y0, self.f)
File "C:\ProgramData\Anaconda3\lib\site-packages\scipy\integrate\_ivp\radau.py", line 343, in jac_wrapped
sparsity)
File "C:\ProgramData\Anaconda3\lib\site-packages\scipy\integrate\_ivp\common.py", line 307, in num_jac
return _dense_num_jac(fun, t, y, f, h, factor, y_scale)
File "C:\ProgramData\Anaconda3\lib\site-packages\scipy\integrate\_ivp\common.py", line 318, in _dense_num_jac
diff = f_new - f[:, None]
IndexError: too many indices for array
I also get an error with method = 'LSODA', although different (i.e. all implicit integrators). I do not get an error with any of the explicit integrators.
I tried this in spyder with scipy version 1.0.0 and in google colab (scipy version 1.1.0), with the same results.
Is this a bug or am I missing some argument I need for implicit integrators??
It appears that the Radau and BDF methods do not handle single-valued RHS functions. Making the function f above output a 1-D list solves your issue. Additionally, as mentioned by Weckesser in the comments, solve_ivp expects the RHS to be f(t, y) and not f(y, t).
Like this
def f(t, y):
return [y]
I am just trying to fit a function which retrieves the correlation Pearson coefficient between two arrays. These two arrays are passed to the function as input parameters but they do not change. For the function, they should be interpreted as constants. I found an option for the parameters where it is possible to fix one parameter, i.e., it can not vary, but it works only for scalar values.
When I call Model.make_params(), the Model Class tries to check of these arrays are lower or grater than the minimum/maximum. This evaluation is not needed as they are constants.
My function:
def __lin_iteration2__(xref, yref_scaled, xobs, yobs, slope, offset, verbose=False, niter=None):
Acal = 1 + (offset + slope*xref)/xref
xr_new = xref * Acal
obs_interp1d = interp1d(xobs, yobs, kind='cubic')
yobs_new = scale_vector(obs_interp1d(xr_new))
rho = Pearson(yref_scaled, yobs_new)
return rho
Where xref, yref_scaled, xobs and yobs are arrays that do not change, i.e., constants. 'interp1d' is the interpolator operator coming from scipy.interpolate, 'scale_vector' scale a vector between -1 and 1, and 'Pearson' calculates the Pearson correlation coefficient.
Who I setup the Model class:
m = Model(corr.__lin_iteration3__)
par = m.make_params(yref_scaled = corr.yref_scaled, \
obs_interp1d=corr.obs_interp1d, offset=0, scale=0)
par['yref_scaled'].vary = False
par['obs_interp1d'].vary = False
r = m.fit
The error I got (just in the second line when I call the 'make_params' function of Model Class):
Traceback (most recent call last):
File "<ipython-input-3-c8f6550e831e>", line 1, in <module>
runfile('/home/andrey/Noveltis/tests/new_correl_sp/new_correl.py', wdir='/home/andrey/Noveltis/tests/new_correl_sp')
File "/usr/lib/python3/dist-packages/spyder/utils/site/sitecustomize.py", line 705, in runfile
execfile(filename, namespace)
File "/usr/lib/python3/dist-packages/spyder/utils/site/sitecustomize.py", line 102, in execfile
exec(compile(f.read(), filename, 'exec'), namespace)
File "/home/andrey/Noveltis/tests/new_correl_sp/new_correl.py", line 264, in <module>
obs_interp1d=corr.obs_interp1d, offset=0, scale=0)
File "/usr/lib/python3/dist-packages/lmfit/model.py", line 401, in make_params
params.add(par)
File "/usr/lib/python3/dist-packages/lmfit/parameter.py", line 338, in add
self.__setitem__(name.name, name)
File "/usr/lib/python3/dist-packages/lmfit/parameter.py", line 145, in __setitem__
self._asteval.symtable[key] = par.value
File "/usr/lib/python3/dist-packages/lmfit/parameter.py", line 801, in value
return self._getval()
File "/usr/lib/python3/dist-packages/lmfit/parameter.py", line 786, in _getval
if self._val > self.max:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
In lmfit, arguments to the model function are expected to be scalar, floating point parameter values, except for "independent variables" which can be any python objects. By default, the first function argument is assumed to be an independent variable, as is any keyword argument with a non-numeric default value. But, you can specify which arguments are the independent variables (and there can be more than one) when creating your model.
I think what you want is:
m = Model(corr.__lin_iteration3__, independent_vars=['xref', 'yref_scaled', 'xobs', 'yobs'])
But also: You could also pass is any Python object, so you could pack your ref and obs data into other structures and do something like
def lin_iteration(Data, slope, offset, verbose=False, niter=None):
Acal = 1 + (offset + slope*Data['xref'])/Data['xref']
xr_new = Data['xref'] * Acal
# or maybe that would be clearer as just
# xr_new = offset + (1+slope)* Data['xref']
obs_interp1d = interp1d(Data['xobs'], Data['yobs'], kind='cubic')
yobs_new = scale_vector(obs_interp1d(xr_new))
rho = Pearson(Data['yref_scaled'], yobs_new)
return rho
and
m = Model(lin_iteration)
par = m.make_params(offset=0, scale=0)
Data = {'xref': xref, 'yref_scaled': yref_scaled, 'xobs': xobs, 'yobs': yobs}
result = m.fit(Data, params)
Of course, that's all untested but it might make your life easier...
I have defined a SymPy piecewise function to compute the Federal Income tax for 2017. I know the function is working as I have tried various inputs and compared it to verified tax calculators and it gives the same result.
However, when trying to plot the SymPy function, I get the error:
TypeError: '>=' not supported between instances of 'complex' and 'int'
I never defined any complex numbers.
def getFedTax(alpha,p,GI):
# alpha is an array indicating the starting dollar amount of each tax bracket, not including 0
#p is an array of the Tax Percentage amount corresponding to the interval BEFORE each alpha, i.e. [0,alpha0) corresponds to p0, [alpha0, alpha1) corresponds to p1, etc.
#x is the Gross Income for computation
# create an array of the cumulative sums for each starting point in alpha
cumsums = [0,p[0]*(alpha[0]-0)]
cumnum = cumsums[1]
for i,num in enumerate(alpha[1:-1],start=1):
cumsums.append(p[i]*(alpha[i]-alpha[i-1]) + cumnum)
cumnum = cumnum + p[i]*(alpha[i]-alpha[i-1])
cumsums.append(p[-2]*(alpha[-1]-alpha[-2]) + cumnum)
#Create the argument list of tuples for the SymPy.Piecewise function
argtuples = []
for n,bracstart in enumerate(alpha):
if n == 0:
argtuples.append((cumsums[0] + p[0]*x, And(0<=x, x<alpha[0])))
elif 0 < n and n < len(alpha)-1:
argtuples.append((cumsums[n] + p[n]*(x - alpha[n-1]), And(alpha[n-1] <= x, x < alpha[n])))
else:
argtuples.append((cumsums[-1]+p[-1]*(x-alpha[-1]), x>alpha[-1]))
t = Piecewise(*argtuples)
return round(t.subs(x,GI),2), t
from sympy import Piecewise, And
from sympy.plotting.plot import plot
from sympy.abc import x
ti = getFedTax([9325.00,37950.00,91900.00,191650.00,416700.00,418400.00],
[0.10,0.15,0.25,0.28,.33,.35,.396],1000000)
plot(ti[1],(x,1.,450000.00))
Full traceback:
runfile('C:/Users/galileo/Downloads/trial.py',
wdir='C:/Users/galileo/Downloads')
File "c:\users\galileo\appdata\local\programs\python\python36\lib\site-
packages\spyder\utils\site\sitecustomize.py", line 710, in runfile
execfile(filename, namespace)
File "c:\users\galileo\appdata\local\programs\python\python36\lib\site-
packages\spyder\utils\site\sitecustomize.py", line 101, in execfile
exec(compile(f.read(), filename, 'exec'), namespace)
File "C:/Users/galileo/Downloads/trial.py", line 39, in <module>
plot(ti[1],(x,1.,450000.00))
File "c:\users\galileo\appdata\local\programs\python\python36\lib\site-
packages\sympy\plotting\plot.py", line 1295, in plot
plots.show()
File "c:\users\galileo\appdata\local\programs\python\python36\lib\site-
packages\sympy\plotting\plot.py", line 196, in show
self._backend.show()
File "c:\users\galileo\appdata\local\programs\python\python36\lib\site-
packages\sympy\plotting\plot.py", line 1029, in show
self.process_series()
File "c:\users\galileo\appdata\local\programs\python\python36\lib\site-
packages\sympy\plotting\plot.py", line 908, in process_series
collection = self.LineCollection(s.get_segments())
File "c:\users\galileo\appdata\local\programs\python\python36\lib\site-
packages\sympy\plotting\plot.py", line 514, in get_segments
f_start = f(self.start)
File "c:\users\galileo\appdata\local\programs\python\python36\lib\site-
packages\sympy\plotting\experimental_lambdify.py", line 231, in __call__
result = self.lambda_func(args)
File "c:\users\galileo\appdata\local\programs\python\python36\lib\site-
packages\sympy\plotting\experimental_lambdify.py", line 316, in __call__
return self.lambda_func(*args, **kwargs)
File "<string>", line 1, in <lambda>
TypeError: '>=' not supported between instances of 'complex' and 'int'
Plotting of piecewise linear was bugged, and seems to have been fixed in january 2018
Upgrading to SymPy 1.2 (from 1.1.1 which was shipped by default with Anaconda) did the trick for me.
from sympy import symbols
from sympy.plotting import plot
x = symbols('x')
from sympy import Piecewise, log
f = 2*x+3
g = x+1
p = Piecewise((-1, x < -1), (g, x <= 1), (f, True))
plot(p)
import matplotlib.pyplot as plt
import numpy as np
import math
from scipy import *
from scipy.integrate import quad, dblquad, tplquad
q=range(1,6)
L=range(1,6)
sigmak=range(1,6)
x_lower = -3000
x_upper = 3000
y_lower = -3000
y_upper = 3000 #Integrate range
def final(a,b): #final(a,b)=0 to be plotted on a-b plane
m=a
n=b
def f3(x,y):
mass=0
for i in range(len(q)):
mass+=(L[i]*exp(-(x*x+y*y/(q[i]*q[i]))/(2*sigmak[i]*sigmak[i])))/(2*3.1415926*q[i]*sigmak[i]*sigmak[i])
return mass*(m-x)/((x-m)**2+(y-n)**2)
val=dblquad(f3,x_lower, x_upper, lambda x : y_lower, lambda x: y_upper)
return val[0]
y,x=np.ogrid[-1000:1000:200j,-1000:1000:200j]# plot range
f=final(x,y)
plt.figure(figsize=(9,4))
plt.subplot(121)
extent=[np.min(x),np.max(x),np.min(y),np.max(y)]
cs=plt.contour(f,extent=extent,levels=[0,0.1],colors=["b","r"],linestyles=["solid","dashed"],linewidths=[2,2])
plt.show()
Above is my codes. And I want to plot final(x,y)=0 in a plane. final(x,y) is a function which is a little complicated.When I run my code, it raises
Traceback (most recent call last):
File "test.py", line 25, in <module>
f=final(x,y)
File "test.py", line 22, in final
val=dblquad(f3,x_lower, x_upper, lambda x : y_lower, lambda x: y_upper)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/scipy/integrate/quadpack.py", line 433, in dblquad
return quad(_infunc,a,b,(func,gfun,hfun,args),epsabs=epsabs,epsrel=epsrel)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/scipy/integrate/quadpack.py", line 252, in quad
retval = _quad(func,a,b,args,full_output,epsabs,epsrel,limit,points)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/scipy/integrate/quadpack.py", line 317, in _quad
return _quadpack._qagse(func,a,b,args,full_output,epsabs,epsrel,limit)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/scipy/integrate/quadpack.py", line 381, in _infunc
return quad(func,a,b,args=myargs)[0]
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/scipy/integrate/quadpack.py", line 252, in quad
retval = _quad(func,a,b,args,full_output,epsabs,epsrel,limit,points)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/scipy/integrate/quadpack.py", line 317, in _quad
return _quadpack._qagse(func,a,b,args,full_output,epsabs,epsrel,limit)
quadpack.error: Supplied function does not return a valid float.
So what's my problem? Thank you if anyone could help me!
Not sure what you are trying to do here
dblquad returns 2 floats, the resultant integral and an estimate of the error.
By making a for loop like below we can export an array but i don't think that's what you need
def final(a,b): #final(a,b)=0 to be plotted on a-b plane
outcome = []
for i in range(len(a)):
#print(i)
print(a[i])
m=a[i]
n=b[i]
def f3(x,y):
mass=0
for i in range(len(q)):
mass+=(L[i]*exp(-(x*x+y*y/(q[i]*q[i]))/(2*sigmak[i]*sigmak[i])))/(2*3.1415926*q[i]*sigmak[i]*sigmak[i])
return mass*(m-x)/((x-m)**2+(y-n)**2)
val=dblquad(f3,a[0], a[-1], lambda x : m, lambda x: a[-1])
outcome.append(val)
return np.array(outcome)
y=np.ogrid[-10:10:10j]
x=np.ogrid[-10:10:10j]
f=final(x,y)
Be more precise in what you are trying to achieve.
I have following codes to plot a gassian-2d contour,but I get this Error:
Traceback (most recent call last):
File "question.py", line 15, in <module>
Z0=gaussian_2d(X0,Y0,2,3,cov)
File "question.py", line 4, in gaussian_2d
return exp(-0.5*mat([x-x0,y-y0])*sigmaMatrix.I*mat([x-x0,y-y0]).T)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/numpy/matrixlib/defmatrix.py", line 96, in asmatrix
return matrix(data, dtype=dtype, copy=False)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/numpy/matrixlib/defmatrix.py", line 272, in __new__
raise ValueError("matrix must be 2-dimensional")
ValueError: matrix must be 2-dimensional
This my code:
import matplotlib.pyplot as plt
from numpy import *
def gaussian_2d(x, y, x0, y0, sigmaMatrix):
return exp(-0.5*mat([x-x0,y-y0])*sigmaMatrix.I*mat([x-x0,y-y0]).T)
cov=mat([[1,0],[0,2]])
delta=0.025
xgrid=arange(-2, 6, delta)
ygrid=arange(-2, 6, delta)
X0, Y0 = meshgrid(xgrid, ygrid)
Z0=gaussian_2d(X0,Y0,2,3,cov)
Can anyone tell me what am i doing wrong here?
Error starts from the concatenation but also your matrix dimensions don't match.
You are performing a quadratic form multiplication x^T A x but your meshgrid variables are square matrices of 320x320. Your A matrix cov is 2x2 hence you get an error.
If the sizes matches you can column concatenate mat(c_[x-x0,y-y0]) or use any other stacking option.