Evaluate absolute value of array element in function - python

I defined a function
def softthresh(u, LAMBDA):
if np.fabs(u) <= LAMBDA:
return 0
else:
return ((np.fabs(u) - LAMBDA) * u / np.fabs(u))
u is a numpy array, and np.fabs will check the relations for each array element (np.fabs(u_i)). It gives me the following error:
The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
Follow up Question:
Strange behaviour in simple function.
def softthresh(u,LAMBDA):
for i in u:
if np.fabs(i)<=LAMBDA:
return 0
else:
return ((np.fabs(i)-LAMBDA)*u/np.fabs(i))
ll = 5.0
xx = np.arange(-10,11)
yy = softthresh(xx,ll)
What I get is not what I expect. for u (=xx ) array-elements that are smaller than 5 i should get zero. But i don't. Why?

You are calling return from inside the inner loop. Therefore, your function returns just after it evaluates the first member of u.
Since you are using NumPy, you should take advantage of NumPy's ability to operate on the whole array at once, and also of NumPy's smart indexing.
def softthreshold(u, LAMBDA):
notzero = np.fabs(u) > LAMBDA # find the indeces of elements that need to be scaled
rr = np.zeros_like(u) # an array the same size/type as u, already initialized to 0
rr[notzero] = (np.fabs(u[notzero])-LAMBDA)*u[notzero]/np.fabs(u[notzero]) # scale each of the members that aren't zero
return rr

Your problems depends on the numpy array. If you are working with a list it works.
Otherwise if you need the numpy array you can use code like
def softthresh(u,LAMBDA):
for i in u:
if np.fabs(i)<=LAMBDA:
return 0
else:
return ((np.fabs(u)-LAMBDA)*u/np.fabs(u))
You get the array through the dependency of <= logic and the numpy.array definition.

If u is an array, you need to loop through all its elements in your function.
Alternatively, you can have u be an element of your array and call it with a loop like this :
tbl = np.array([1, 2, 3, 4, 5])
for elt in tbl:
print(softthresh(elt, 3))
Results would be :
0
0
0
1.0
2.0

Related

ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all() while simulation observations

I want to simulate some observations from a uniform distribution and a 2 dimensional normal distribution and calculate the mean, but I get the error
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
in line 5, but when I change A != None to A.any() == True I get AttributeError: 'list' object has no attribute 'any' how can I fix this?
import numpy as np
import random
def getmean(A):
if A != None:
return np.sum(A)/len(A)
else:
return 0
for n in [1, 50, 1000]:
unifs = []
normals = []
# uniform
for i in range(n):
unifs.append(random.random())
# normal
for i in range(n):
normals.append(np.array([np.random.normal(0, 1),
np.random.normal(0, 1)]))
normals = np.array(normals)
print("n:", n, "normal mean:", getmean(unifs))
print("n:", n, "unif mean:", getmean(normals))
I understand why you use if A != None: comparison or why you need any() for the purpose you said in your question but you just need to check if A has any member or not and for this purpose, you can use any of the following methods instead:
...
if A:
...
or
...
if len(A):
...
or
...
if len(A) != 0:
...
But anyway, I explain any() function here for you.
list or other data structure in python doesn't have .any() method themselves. There is a function called any() and you can use for all iterable objects in python like list, tuple etc. and you can use it in this way:
sample_list = [0, 1, 2]
print(any(sample_list))
# prints: True
sample_list2 = [] # or [0, 0, 0]
print(any(sample_list2))
# prints: False

np.argmax to return -1 if all values in the input are the same

I want to use np.argmax but I want to get -1 (or any other number) when all the elements in the array input are the same or if there are multiple occurences of them. For example, a = np.array([2, 2, 2]) -> I want to get -1 instead of 0. Is there any alternative function?
I do not know of such a function, but you could always write it yourself, e.g. like this:
import numpy as np
def my_index(arr):
"""
Input: arr should be a NumPy array.
Return -1 if at least one number in arr occurs more than once.
Else return the index of the maximum number.
"""
flat = arr.ravel()
if len(np.unique(flat)) < len(flat):
return -1
return np.argmax(arr)

np.vectorize fails on a 2-d numpy array as input

I am trying to vectorize a function that takes a numpy array as input. I have a 2-d numpy array (shape is 1000,100) on which the function is to be applied on each of the 1000 rows. I tried to vectorize the function using np.vectorize. Here is the code:
def fun(i):
print(i)
location = geocoder.google([i[1], i[0]], method="reverse")
#print type(location)
location = str(location)
location = location.split("Reverse")
if len(location) > 1:
location1 = location[1]
return [i[0], i[1], location1]
#using np.vectorize
vec_fun = np.vectorize(fun)
Which raises the error
<ipython-input-19-1ee9482c6161> in fun(i)
1 def fun(i):
2 print(i)
----> 3 location = geocoder.google([i[1], i[0]], method="reverse")
4 #print type(location)
5 location = lstr(location)
IndexError: invalid index to scalar variable.
I have printed the argument that is passed in to the fun which prints a single value (the first element of the vector) rather than the vector(1 row) that is the reason of the index error but I'm not getting any idea how to resolve this.
By this time I think yo have solved your problem. However, I just found a way that solve this and may help other people with the same question. You can pass a signature="str" parameter to np.vectorize in order to specify the input and output shape. For example, the signature "(n) -> ()" expects an input shape with length (n) (rows) and outputs a scalar (). Therefore, it will broadcast up to rows:
def my_sum(row):
return np.sum(row)
row_sum = np.vectorize(my_sum, signature="(n) -> ()")
my_mat = np.array([
[1, 1, 1],
[2, 2, 2],
])
row_sum(my_mat)
OUT: array([3, 6])
vectorize runs your function on each element of an array, so it's not the right choice. Use a regular loop instead:
for row in some_array:
i0, i1, loc = fun(row)
It's up to you as to what you want to do with the output. Keep in mind that your function does not assign location1 if len(location) <= 1, and will raise an error in that case. It also returns a string rather than a numerical value in the third output.
Once you fix those issues, if you want to make an array of the output:
output = np.empty((some_array.shape[0], 3))
for i, row in enumerate(some_array):
output[i, :] = fun(row)

Python: element-wise comparison of array to non-array

I'm trying to plot some complex functions using numpy. Example of some working code:
import numpy as np
from PIL import Image
size = 1000
w = np.linspace(-10, 10, size)
x, y = np.meshgrid(w, w)
r = x + 1j*y
def f(q):
return np.angle(q)
z = f(r)
normalized = ((255/(np.amax(z) - np.amin(z)))*(z+abs(np.amin(z)))).astype(int)
data = [i for j in normalized for i in j]
img = Image.new('L', (size, size))
img.putdata(data[::-1]) #pixels are done bottom to top
img.show()
However, suppose I want the function f to have a simple comparison in it, like this:
def f(q):
if np.abs(q) < 4:
return 1
else:
return 0
I get the error
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
For the np.abs(q) < 4 check.
I did some digging and realized it's because Python is doing the operation on the entire r array, and it can't compare an array to an integer. So, I tried looking for ways to do element-wise comparisons.
This page looked promising: it says I can do element-wise comparisons by using np.less(a, b), so I tried
def f(q):
if np.less(np.abs(q), 4):
return 1
else:
return 0
and got the same ValueError. It seems as though both arguments for np.less() need to be arrays of the same size.
What I want is to compare each element of my array to a single, non-array quantity. I suppose I could make a dummy array of the same size filled with identical 4's, but there has to be a more elegant way of doing this.
The key is to return an array value instead of trying to coerce an array into a single bool, which is what if (some_array): keeps trying to do. There being no unambiguous way to decide what single boolean np.array([True, False]) should convert to, it doesn't even try.
So don't even branch:
def f(q):
return abs(q) < 4
gives an array like
>>> f(np.array([1,3,5]))
array([ True, True, False], dtype=bool)
which as numbers will behave like
>>> f(np.array([1,3,5])).astype(int)
array([1, 1, 0])
and give

Weird error when trying to compare numbers

Consider the next piece of code -
def findBestHypothesis():
bestOfBest = []
currentERMValue = 0
bestERMValue = 0
for polynom in bestOfHypothesisClasses:
for j in range(0, len(training_set)):
currentERMValue += (np.polyval(polynom, training_set[x_value_index]) -
training_set[y_value_index])**2
if currentERMValue >= bestERMValue:
bestERMValue = currentERMValue
currentERMValue = 0
bestOfBest = polynom
return bestOfBest
As you can see, currentERMValue and bestERMValue are numbers and not arrays. But yet i get this -
if np.greater_equal(currentERMValue, bestERMValue): ValueError: The
truth value of an array with more than one element is ambiguous. Use
a.any() or a.all()
polyval on an array returns an array, one element for each x value:
>>> np.polyval([1,2,3],[4,5,6])
array([27, 38, 51])
so either training_set is a two dimensional array, or x_value_index or y_value_index are not scalars.
I am not sure, but np.polyval return several values.
Returns:
values : ndarray or poly1d
If x is a poly1d instance, the result is the composition of the two polynomials, i.e., x is “substituted” in p and the simplified result is returned. In addition, the type of x - array_like or poly1d - governs the type of the output: x array_like => values array_like, x a poly1d object => values is also.
http://docs.scipy.org/doc/numpy-1.10.1/reference/generated/numpy.polyval.html

Categories

Resources