I have a conditional function, say f(x), that takes domain values from a numpy.ndarray the_array and maps into another numpy.ndarray, result
f(x) = g(x) if x>0
h(x) otherwise
g(x) and h(x) here are some other functions.
Looks to me something like the following, but I don't know how to refer to the corresponding array entries in the ternary if:
result = g(the_array) if <??> else h(the_array)
If there's no problem valuating g(x) and h(x) for all of x, then
result = np.where( x>0, g(x), h(x))
If g can be evaluated only at x>0, we have to do more work. For example:
mask = x>0
result = h(x)
result[mask] = g(x[mask])
Some ufunc take where and out parameters that work like this. If g is a ufunc:
g(x, where=x>0, out = h(x))
result = the_array
for i in range(len(the_array)):
result[i] = g(the_array[i]) if the_array[i] > 0 else h(the_array[i])
you can use this array based operation assuming your g and h function can accept all values as input (meaning g does not through error/exception for non-positive values and h for positive values). The equation is quite self explanatory of the if statement in question:
result = g(x)*(x>0) + h(x)*(x<=0)
And if your g function only accepts positives and h function only accepts non-positives, you can mask array x and do operations and merge them like this:
idx_p = np.argwhere(x>0)
idx_np = np.argwhere(x<=0)
result = np.zeros_like(x)
result[idx_p] = g(x[x>0].reshape(-1, 1))
result[idx_np] = h(x[x<=0].reshape(-1, 1))
example code:
x = np.array([-1,1,-2,2])
def g(x):
return x**2
def h(x):
return x
result = g(x)*(x>0) + h(x)*(x<=0)
output:
[-1 1 -2 4]
As long as your function is quick to evaluate, you can use numpy.where:
import numpy as np
def g(x):
return x * 2
def h(x):
return x * 10
x = np.arange(-5, 5)
result = np.where(x > 0, g(x), h(x))
After this, result is
array([-50, -40, -30, -20, -10, 0, 2, 4, 6, 8])
Related
I have a set of data in a numpy array - x-values, lets say between 0-100, and y-values. I need to get the gradient to a specific x-value ex. x=20 but I can only get the np.gradient function to give me the gradient at a certain index-value. right now I have:
g=np.gradient(y)
print(g[20])
but this of course gives me the gradient at i=20 and not x=20
I have both the x and y values in one 2D array and 2 x 1D arrays defined in my script
EDIT:
I actually came to solve it like this:
def grad(x, value):
def find_nearest(x, value):
x = np.asarray(Timeppmh)
idx = (np.abs(x - value)).argmin()
i = x.tolist().index(x[idx])
return i
g=np.gradient(yp,x)
find_nearest(x,value)
return g[find_nearest(x,value)]
If the value 20 is in x you could just do j[x == 20]. However, if that is not the case, you would need to approximate the gradient value. You can use for example linear interpolation.
import numpy as np
x = np.linspace(0, 100, 80)
print(20 in x) # 20 is not in x
# False
y = x * x + 3 * x + 2
# Pass x as second argument for value spacing
g = np.gradient(y, x)
print(np.interp(20, x, g)) # Should be 43
# 43.00000000000001
I'm trying to sum a two dimensional function using the array method, somehow, using a for loop is not outputting the correct answer. I want to find (in latex) $$\sum_{i=1}^{M}\sum_{j=1}^{M_2}\cos(i)\cos(j)$$ where according to Mathematica the answer when M=5 is 1.52725. According to the for loop:
def f(N):
s1=0;
for p1 in range(N):
for p2 in range(N):
s1+=np.cos(p1+1)*np.cos(p2+1)
return s1
print(f(4))
is 0.291927.
I have thus been trying to use some code of the form:
def f1(N):
mat3=np.zeros((N,N),np.complex)
for i in range(0,len(mat3)):
for j in range(0,len(mat3)):
mat3[i][j]=np.cos(i+1)*np.cos(j+1)
return sum(mat3)
which again
print(f1(4))
outputs 0.291927. Looking at the array we should find for each value of i and j a matrix of the form
mat3=[[np.cos(1)*np.cos(1),np.cos(2)*np.cos(1),...],[np.cos(2)*np.cos(1),...]...[np.cos(N+1)*np.cos(N+1)]]
so for N=4 we should have
mat3=[[np.cos(1)*np.cos(1) np.cos(2)*np.cos(1) ...] [np.cos(2)*np.cos(1) ...]...[... np.cos(5)*np.cos(5)]]
but what I actually get is the following
mat3=[[0.29192658+0.j 0.+0.j 0.+0.j ... 0.+0.j] ... [... 0.+0.j]]
or a matrix of all zeros apart from the mat3[0][0] element.
Does anybody know a correct way to do this and get the correct answer? I chose this as an example because the problem I'm trying to solve involves plotting a function which has been summed over two indices and the function that python outputs is not the same as Mathematica (i.e., a function of the form $$f(E)=\sum_{i=1}^{M}\sum_{j=1}^{M_2}F(i,j,E)$$).
The return statement is not indented correctly in your sample code. It returns immediately in the first loop iteration. Indent it on the function body instead, so that both for loops finish:
def f(N):
s1=0;
for p1 in range(N):
for p2 in range(N):
s1+=np.cos(p1+1)*np.cos(p2+1)
return s1
>>> print(f(5))
1.527247272700347
I have moved your code to a more numpy-ish version:
import numpy as np
N = 5
x = np.arange(N) + 1
y = np.arange(N) + 1
x = x.reshape((-1, 1))
y = y.reshape((1, -1))
mat = np.cos(x) * np.cos(y)
print(mat.sum()) # 1.5272472727003474
The trick here is to reshape x to a column and y to a row vector. If you multiply them, they are matched up like in your loop.
This should be more performant, since cos() is only called 2*N times. And it avoids loops (bad in python).
UPDATE (regarding your comment):
This pattern can be extended in any dimension. Basically, you get something like a crossproduct. Where every instance of x is matched up with every instance of y, z, u, k, ... Along the corresponding dimensions.
It's a bit confusing to describe, so here is some more code:
import numpy as np
N = 5
x = np.arange(N) + 1
y = np.arange(N) + 1
z = np.arange(N) + 1
x = x.reshape((-1, 1, 1))
y = y.reshape((1, -1, 1))
z = z.reshape((1, 1, -1))
mat = z**2 * np.cos(x) * np.cos(y)
# x along first axis
# y along second, z along third
# mat[0, 0, 0] == 1**2 * np.cos(1) * np.cos(1)
# mat[0, 4, 2] == 3**2 * np.cos(1) * np.cos(5)
If you use this for many dimensions, and big values for N, you will run into memory problems, though.
Suppose I have some matrix X where each row represents a time-series. For example, X could be a matrix of size 3 x 1000, which would mean that there are 3 time-series each consisting of 1000 time-points. In addition to X, I have one scalar for each time-series in X. I would like to find a linear combination
a[0] * X[0, :] + a[1] * X[1, :] + ... + a[n-1] * X[n-1, :]
that has the minimum value for some function F.
So, I attempted the following
import numpy as np
from scipy.optimization import minimize
def f(x):
return 0 # for testing purposes
def obj(a,x):
y = a*x
return f(y)
minimize(obj, np.array([1,1]), args=np.array([[1,1],[2,2]]), method='nelder-mead')
So the second argument is the initial guess x0 (the coefficients a). The data given by args should get mapped to x (if I understand it correctly) and remains constant during the optimization.
However, I get the error
ValueError: setting an array element with a sequence.
I guess my problem is pretty general one, so I hope someone would be able to help!
Something like this?
import scipy.optimize as opt
def f(val):
return val**2
def obj(a, series):
s = 0
for row in series:
for t in range(len(row)):
s += f(a[t] * row[t])
return s
ll_x = [[2, 3, 2, 6], [3, 5, 2, 7]] # 2 series
l_a = [1 for _ in ll_x[0]] # initial coeffs.
res = opt.minimize(obj, l_a, args=ll_x, method='nelder-mead')
for elem in sorted(res.items()):
print(*elem)
(works for me with Python 3.4.3)
I wrote a differentiable Heaviside function and vectorised it. However, the output seems to be odd and binary. The code is as follows:
import numpy as np
import matplotlib.pyplot as plt
def heaviside(x, epis):
if (x>= epis):
y=1
elif (x< -epis):
y=0;
else:
y = 0.5 + x/(2*epis) + np.sin(np.pi*x/epis)/(2*np.pi);
print (x, y);
return y;
x1 = np.linspace(-1, 1, 100);
vheaviside = np.vectorize(heaviside);
y1 = vheaviside(x1, 0.2);
plt.plot(x1, y1, 'b', alpha=0.3)
plt.show()
The input is an array in [-1, 1], and the outputs are supposed to be a continuous Heaviside function. However, all of the output is 0 or 1. Why?
You need to specify when you vectorize the function that it should be using floats:
vheaviside = np.vectorize(heaviside, [float])
otherwise, per the documentation:
The output type is determined by evaluating the first element of the input
which in this case is an integer. Alternatively, make sure heaviside always returns a float, by replacing e.g. y = 1 with y = 1.0.
A simpler and more efficient way of defining a vectorized Heaviside function with Numpy would be using numpy.piecewise:
def heaviside(x, epis):
return np.piecewise(x, (x>=epis, x<-epis),
(1, 0, lambda x: 0.5 + x/(2*epis) + np.sin(np.pi*x/epis)/(2*np.pi) ) )
As far as I know there is only discontinuous one.Try this:
def h(x):
if x == 0:
return 0.5
return 0 if x < 0 else 1
How do I find the maximum of a function in Python? I could try to hack together a derivative function and find the zero of that, but is there a method in numpy (or other library) that can do it for me?
You can use scipy.optimize.fmin on the negative of your function.
def f(x): return -2 * x**2 + 4 * x
max_x = scipy.optimize.fmin(lambda x: -f(x), 0)
# array([ 1.])
If your function is solvable analytically try SymPy. I'll use EMS's example above.
In [1]: from sympy import *
In [2]: x = Symbol('x', real=True)
In [3]: f = -2 * x**2 + 4*x
In [4]: fprime = f.diff(x)
In [5]: fprime
Out[5]: -4*x + 4
In [6]: solve(fprime, x) # solve fprime = 0 with respect to x
Out[6]: [1]
Of course, you'll still need to check that 1 is a maximizer and not a minimizer of f
In [7]: f.diff(x).diff(x) < 0
Out[7]: True
I think scipy.optimize.minimize_scalar and scipy.optimize.minimize are the preferred ways now, that give you access to the range of techniques, e.g.
solution = scipy.optimize.minimize_scalar(lambda x: -f(x), bounds=[0,1], method='bounded')
for a single variable function that must lie between 0 and 1.
You could try SymPy. SymPy might be able to provide you with the derivative symbolically, find its zeros, and so on.
Maximum of a function with parameters.
import scipy.optimize as opt
def get_function_max(f, *args):
"""
>>> round(get_function_max(lambda x, *a: 3.0-2.0*(x**2)), 2)
3.0
>>> round(get_function_max(lambda x, *a: 3.0-2.0*(x**2)-2.0*x), 2)
3.5
>>> round(get_function_max(lambda x, *a: a[0]-a[1]*(x**2)-a[1]*x, 3.0, 2.0), 2)
3.5
"""
def func(x, *arg):
return -f(x, *arg)
return f(opt.fmin(func, 0, args=args, disp=False)[0], *args)