Lets say I have the following function:
def f(x):
return log(3*exp(3*x) + 7*exp(7*x))
I want to do two things:
1) plot the function over a range of x-values
2) find the root of the function using the Newton method from scipy
My problem is that it seems that plotting is best done with a numpy array x=np.linspace(-2,2,1000), but then evaluating the function results in erros TypeError: only size-1 arrays can be converted to Python scalars. I can fix this by simply changing log and exp to np.log and np.exp, respectively.
But doing so then makes scipy.optimize.newton unhappy.
It seems like I need to define the function twice, once for use in plotting (with np. ...) and once for optimizing in the form given above.
I can't imagine that this is actually the case. Any hints would be greatly appreciated.
Seems legit, you just need to use numpy functions instead of base math functions:
import numpy as np
from scipy import optimize
import matplotlib.pyplot as plt
%matplotlib inline
def f(x):
return np.log(3*np.exp(3*x) + 7*np.exp(7*x))
x = np.linspace(-2,2,1000)
y = f(x)
plt.scatter(x, y)
optimize.root(f, 1)
Related
I am using SymPy for analytical handling of variables (e.g. matrix multiplication etc.).
After doing so, I end up with a new SymPy expression which I would like to use for plotting with Matplotlib. So far, my only way to do so, was to print the SymPy expression and paste it into a newly defined function manually.
How can I directly convert the SymPy expression into a function for numerical interpretation without relying on copying and pasting?
A minimal working example is the following:
import sympy as sp
import matplotlib.pyplot as plt
import numpy as np
sp.var('x A B') # x will later be the variable, A and B will be constants
temp = A*x+B # intermediate calculations
f = temp*x # function in reality, it will be more complicated.
print(f) # I printed f in order to find the expression and copy-pasting it into the function below.
def func(x,A,B):
return x*(A*x + B) # This statement was copy-pasted. This line should be changed, s.t. copy-pasting is not necessary!
#Now we can handle the function numerically for plotting (using matplotlib and numpy)
xspace = np.linspace(0,5)
plt.plot(xspace,func(x=xspace,A=1,B=2))
Sympy’s lambdify exists exactly for this. Just replace your definition of func with:
func = sp.lambdify((x,A,B),f)
I need the values of the autocorrelation coefficients coming from the autocorrelation_plot(). The problem is that the output coming from this function is not accessible, so I need another function to get such values. That's why I used acf() from statsmodels but it didn't get the same plot as autocorrelation_plot() does. Here is my code:
from statsmodels.tsa.stattools import acf
from pandas.plotting import autocorrelation_plot
import matplotlib.pyplot as plt
import numpy as np
y = np.sin(np.arange(1,6*np.pi,0.1))
plt.plot(acf(y))
plt.show()
So the result is not the same as this:
autocorrelation_plot(y)
plt.show()
This seems to be related to the nlags parameter of acf:
nlags: int, optional
Number of lags to return autocorrelation for.
I don't know what exactly this does but in the source of acf there is a slicing
that shortens the array:
avf = acovf(x, unbiased=unbiased, demean=True, fft=fft, missing=missing)
acf = avf[:nlags + 1] / avf[0]
If you use statsmodels.tsa.stattools.acovf directly the result is the same as with autocorrelation_plot:
avf = acovf(x, unbiased=unbiased, demean=True, fft=fft, missing=missing)
So you can call it like
plt.plot(acf(y, nlags=len(y)))
to make it work.
An explanation of lag: https://math.stackexchange.com/questions/2548314/what-is-lag-in-a-time-series/2548350
I'd like to calculate an integral of the form
where I want the results as an array (to eventually plot them as a function of omega). I have
import numpy as np
import pylab as plt
from scipy import integrate
w = np.linspace(-5, 5, 1000)
def g(x):
return np.exp(-2*x)
def complexexponential(x, w):
return np.exp(-1j*w*x)
def integrand(x, w):
return g(x)*complexexponential(x, w)
integrated = np.real(integrate.quad(integrand, 0, np.inf, args = (w)))
which gives me the error "supplied function does not return a valid float". I am not very familiar with the integrate-function of Scipy. Many thanks for your help in advance!
Scipy integrate.quad doesn't seem to support vector output. If you loop over all your values of w and only give one of them at a time as args your code seems to work fine.
Also it doesn't handle complex integration, which you can get around using the procedure outlined in this answer.
I tried to plot the output of the defined function with respect to z. However the error TypeError: unhashable type: 'numpy.ndarray' is shown. Please help.
import numpy as np
import matplotlib.pyplot as plt
import sympy as sp
a=1.48185562
b=0.57081914
c=-0.25098188
H0=70.32724312
z=np.linspace(0.0,1.5,100)
omega_m0=0.3
dlabel= 'w(z) vz z'
def func(z):
sp.var('z+1')
H=((2/H0)*((b*(z+1)+c*(z+1)**0.5+2.0-a-b-c)*(1-0.5*a*(z+1)**(-0.5)) - ((z+1)-a*(z+1)**0.5-1.0+a)*(b+c*0.5*(z+1)**(-0.5)))/(b*(z+1)+c*(z+1)**0.5+2.0-a-b-c)**2)**(-1)
return ((2*(z+1)/3)*(sp.diff(sp.log(H)))-1)/(1-(H/H0)**2*omega_m0*(z+1)**3)
wz=func(z)
plt.plot(z,wz)
plt.xlabel('z')
plt.ylabel('w(z)')
plt.show()
I'm not sure what you want to do with sp.var('z+1')... at least I hope you were not trying to create a variable named z+1. I got the code to run but I let you make sure it does what you want and complain if not :)
import numpy as np
import matplotlib.pyplot as plt
import sympy as sp
a=1.48185562
b=0.57081914
c=-0.25098188
H0=70.32724312
x=np.linspace(0.0,1.5,100)
omega_m0=0.3
dlabel= 'w(z) vz z'
sp.var('z')
def func(z):
H=((2/H0)*((b*(z+1)+c*(z+1)**0.5+2.0-a-b-c)*(1-0.5*a*(z+1)**(-0.5)) - ((z+1)-a*(z+1)**0.5-1.0+a)*(b+c*0.5*(z+1)**(-0.5)))/(b*(z+1)+c*(z+1)**0.5+2.0-a-b-c)**2)**(-1)
return ((2*(z+1)/3)*(sp.diff(sp.log(H)))-1)/(1-(H/H0)**2*omega_m0*(z+1)**3)
wz = [func(z).evalf(subs = {z : y}) for y in x]
plt.plot(x,wz)
plt.xlabel('z')
plt.ylabel('w(z)')
plt.show()
EDIT: in order to get wz, the following piece is much faster ( cf Evaluate sympy expression from an array of values ):
from sympy.utilities.lambdify import lambdify
func_np_ready = lambdify(z, func(z),'numpy') # returns a numpy-ready function
wz = func_np_ready(x)
You may be better off flagging your question with sympy - it's probably the behaviour of one of those functions that's causing the issue, and someone else might know all about it.
It's probably a good idea to split those really long formulas up into multi lines (at least while debugging) to help you track down the error. Also put in some prints etc.
I know it's not what you want to achieve but if I cut out the sympy (I don't have it installed!) and adjust the array lengths it plots without error:
...
H=((2/H0)*((b*(z+1)+c*(z+1)**0.5+2.0-a-b-c)*(1-0.5*a*(z+1)**(-0.5)) - ((z+1)-a*(z+1)**0.5-1.0+a)*(b+c*0.5*(z+1)**(-0.5)))/(b*(z+1)+c*(z+1)**0.5+2.0-a-b-c)**2)**(-1)
return ((2*(z[:-1]+1)/3)*(np.diff(np.log(H)))-1)/(1-(H[:-1]/H0)**2*omega_m0*(z[:-1]+1)**3)
wz=func(z)
plt.plot(z[:-1],wz)
Is there a built-in Numpy function to convert a complex number in polar form, a magnitude and an angle (degrees) to one in real and imaginary components?
Clearly I could write my own but it seems like the type of thing for which there is an optimised version included in some module?
More specifically, I have an array of magnitudes and an array of angles:
>>> a
array([1, 1, 1, 1, 1])
>>> b
array([120, 121, 120, 120, 121])
And what I would like is:
>>> c
[(-0.5+0.8660254038j),(-0.515038074+0.8571673007j),(-0.5+0.8660254038j),(-0.5+0.8660254038j),(-0.515038074+0.8571673007j)]
There isn't a function to do exactly what you want, but there is angle, which does the hardest part. So, for example, one could define two functions:
def P2R(radii, angles):
return radii * exp(1j*angles)
def R2P(x):
return abs(x), angle(x)
These functions are using radians for input and output, and for degrees, one would need to do the conversion to radians in both functions.
In the numpy reference there's a section on handling complex numbers, and this is where the function you're looking for would be listed (so since they're not there, I don't think they exist within numpy).
There's an error in the previous answer that uses numpy.vectorize - cmath.rect is not a module that can be imported. Numpy also provides the deg2rad function that provides a cleaner piece of code for the angle conversion. Another version of that code could be:
import numpy as np
from cmath import rect
nprect = np.vectorize(rect)
c = nprect(a, np.deg2rad(b))
The code uses numpy's vectorize function to return a numpy style version of the standard library's cmath.rect function that can be applied element wise across numpy arrays.
I used cmath with itertools:
from cmath import rect,pi
from itertools import imap
b = b*pi/180 # convert from deg to rad
c = [x for x in imap(rect,a,b)]
import numpy as np
import cmath.rect
nprect = np.vectorize(rect)
c = nprect(a,b*np.pi/180)
tom10 answer works fine... you can also expand the Euler's formula to:
def P2R(A, phi):
return A * ( np.cos(phi) + np.sin(phi)*1j )