Comparing scalars to Numpy arrays [duplicate] - python

This question already has an answer here:
Numpy error in Python
(1 answer)
Closed 6 years ago.
What I am trying to do is make a table based on a piece-wise function in Python. For example, say I wrote this code:
import numpy as np
from astropy.table import Table, Column
from astropy.io import ascii
x = np.array([1, 2, 3, 4, 5])
y = x * 2
data = Table([x, y], names = ['x', 'y'])
ascii.write(data, "xytable.dat")
xytable = ascii.read("xytable.dat")
print xytable
This works as expected, it prints a table that has x values 1 through 5 and y values 2, 4, 6, 8, 10.
But, what if I instead want y to be x * 2 only if x is 3 or less, and y to be x + 2 otherwise?
If I add:
if x > 3:
y = x + 2
it says:
The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
How do I code my table so that it works as a piece-wise function? How do I compare scalars to Numpy arrays?

You can possibly use numpy.where():
In [196]: y = np.where(x > 3, x + 2, y)
In [197]: y
Out[197]: array([2, 4, 6, 6, 7])
The code above gets the job done in a fully vectorized manner. This approach is generally more efficient (and arguably more elegant) than using list comprehensions and type conversions.

Start off not using numpy (or maybe you can, I don't know numpy) and just do in using regular python lists.
x = [ 1, 2, 3, 4, 5 ]
y = [ i * 2 if i < 3 else i + 2 for i in x ]
print y
Outputs:
[2, 4, 5, 6, 7]
Then you can make it a numpy array:
x = np.array(x)
y = np.array(y)

Related

Python: Can I use the AND operator in an array index? [duplicate]

This question already has answers here:
Logical operators for Boolean indexing in Pandas
(4 answers)
How to perform element-wise Boolean operations on NumPy arrays [duplicate]
(4 answers)
Closed 1 year ago.
I have a list of values, x, and y:
x = [1, 2, 3, 4, 5, 6, 7]
y = [1, 3, 5, 8, 44, 8,0]
Which I convert to arrays:
x = np.array(x)
y = np.array(y)
When I try to print the corresponding y-values for a specified range of x, say x < 5, I get the correct output:
y_new = y[x < 5]
print(y_new)
Output: [1 3 5 8]
However, when I try to retrieve the values of y for 1 < x < 5, I get the following error:
y_1_5 = y[1 < x < 5]
y_15 = y[x > 1 and x < 5]
print(y_1_5)
print(y_15)
Ouput: ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
How do I fix this error because I want to print values of y for 1 < x < 5?
Your help will be much appreciated. Thank you in advance.

"Multiply" 1d numpy array with a smaller one and sum the result

I want to "multiply" (for lack of better description) a numpy array X of size M with a smaller numpy array Y of size N, for every N elements in X. Then, I want to sum the resulting array (almost like a dotproduct).
I hope the example makes it more clear:
Example
X = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Y = [1,2,3]
Z = mymul(X, Y)
= [0*1, 1*2, 2*3, 3*1, 4*2, 5*3, 6*1, 7*2, 8*3, 9*1]
= [ 0, 2, 6, 3, 8, 15, 6, 14, 24, 9]
result = sum(Z) = 87
X and Y can be of varying lengths and Y is always smaller than X, but not necessarily divisible (e.g. M % N != 0)
I have some solutions but they are quite slow. I'm hoping there is a faster way to do this.
import numpy as np
X = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], dtype=int)
Y = np.array([1,2,3], dtype=int)
# these work but are slow for large X, Y
# simple for-loop
t = 0
for i in range(len(X)):
t += X[i] * Y[i % len(Y)]
print(t) #87
# extend Y M/N times so np.dot can be applied
Ytiled = np.tile(Y, int(np.ceil(len(X) / len(Y))))[:len(X)]
t = np.dot(X, Ytiled)
print(t) #87
Resize Y to same length as X and then use matrix-multiplication -
In [52]: np.dot(X, np.resize(Y,len(X)))
Out[52]: 87
Alternative to using np.resize would be with tiling. Hence, np.tile(Y,(m+n-1)//n)[:m] for m,n = len(X), len(Y), could replace np.resize(Y,len(X)) for a faster one.
Another without resizing Y to achieve memory-efficiency -
In [79]: m,n = len(X), len(Y)
In [80]: s = n*(m//n)
In [81]: X2D = X[:s].reshape(-1,n)
In [82]: X2D.dot(Y).sum() + np.dot(X[s:],Y[:m-s])
Out[82]: 87
Alternatively, we can use np.einsum('ij,j->',X2D,Y) to replace X2D.dot(Y).sum().
You can use convolve (documentation):
np.convolve(X, Y[::-1], 'same')[::len(Y)].sum()
Remember to reverse the second array.

Is numpy.multiply always equivalent to the * operator? [duplicate]

This question already has answers here:
Numpy np.multiply vs *-Operator [duplicate]
(2 answers)
Closed 4 years ago.
The numpy.multiply documentation says:
Equivalent to x1 * x2 in terms of array broadcasting.
Is np.multiply(x1, x2) different to x1 * x2 in any circumstance?
Where would I find the implementations of each?
Note: An analogous question exists for division but it doesn't mention multiplication, nor imply that the the answer would be the same in the multiplicative case.
This question also asks for implementation details specific to multiplication.
Supplementing #COLDSPEED's answer I'd like to stress that for non array operands results can actually be quite different:
>>> import numpy as np
>>>
>>> 2 * [1, 2]
[1, 2, 1, 2]
>>> np.multiply(2, [1, 2])
array([2, 4])
Yes, np.multiply and the multiplication operator * work consistently for ndarray objects.
In [560]: x = np.array([1, 2, 3])
In [561]: y = np.array([4, 5, 6])
In [562]: x * y
Out[562]: array([ 4, 10, 18])
In [563]: np.multiply(x, y)
Out[563]: array([ 4, 10, 18])
The only major difference is in terms of matrix objects, for which, the * is setup to perform matrix multiplication (i.e., the dot product).
In [564]: x, y = map(np.matrix, (x, y))
In [565]: np.multiply(x, y)
Out[565]: matrix([[ 4, 10, 18]])
In [566]: x * y
ValueError: shapes (1,3) and (1,3) not aligned: 3 (dim 1) != 1 (dim 0)
Also, as #PaulPanzer mentioned in his answer, they behave differently when multiplying pure-python lists with scalars.

Assigning the same value to different positions in a list in python

Assume that I have the following list in python:
x = [1,2,3,4,5,6,7,8,9,10]
I would like to assign the value 0 to specific positions on the list, for example positions 0, 7 and 9. Could I do something like the following in python without resorting to a loop?
x[0,7,9] = 0
There you go:
x[0] = x[7] = x[9] = 0
Also you can do this with numpy arrays in a more general and flexible fashion:
>>> import numpy as np
>>> x = np.array([1,2,3,4,5,6,7,8,9,10])
>>> indices = [0,7,9]
>>> x[indices] = 0 # or just x[[0,7,9]] = 0
>>> x
array([0, 2, 3, 4, 5, 6, 7, 0, 9, 0])
but this is probably not what you are looking for, as numpy is a slightly more advanced thing.

Euclidean distances between several images and one base image

I have a matrix X of dimensions (30x8100) and another one Y of dimensions (1x8100). I want to generate an array containing the difference between them (X[1]-Y, X[2]-Y,..., X[30]-Y)
Can anyone help?
All you need for that is
X - Y
Since several people have offered answers that seem to try to make the shapes match manually, I should explain:
Numpy will automatically expand Y's shape so that it matches with that of X. This is called broadcasting, and it usually does a very good job of guessing what should be done. In ambiguous cases, an axis keyword can be applied to tell it which direction to do things. Here, since Y has a dimension of length 1, that is the axis that is expanded to be length 30 to match with X's shape.
For example,
In [87]: import numpy as np
In [88]: n, m = 3, 5
In [89]: x = np.arange(n*m).reshape(n,m)
In [90]: y = np.arange(m)[None,...]
In [91]: x.shape
Out[91]: (3, 5)
In [92]: y.shape
Out[92]: (1, 5)
In [93]: (x-y).shape
Out[93]: (3, 5)
In [106]: x
Out[106]:
array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14]])
In [107]: y
Out[107]: array([[0, 1, 2, 3, 4]])
In [108]: x-y
Out[108]:
array([[ 0, 0, 0, 0, 0],
[ 5, 5, 5, 5, 5],
[10, 10, 10, 10, 10]])
But this is not really a euclidean distance, as your title seems to suggest you want:
df = np.asarray(x - y) # the difference between the images
dst = np.sqrt(np.sum(df**2, axis=1)) # their euclidean distances
use array and use numpy broadcasting in order to subtract it from Y
init the matrix:
>>> from numpy import *
>>> a = array([[1,2,3],[4,5,6]])
Accessing the second row in a:
>>> a[1]
array([4, 5, 6])
Subtract array from Y
>>> Y = array([3,9,0])
>>> a - Y
array([[-2, -7, 3],
[ 1, -4, 6]])
Just iterate rows from your numpy array and you can actually just subtract them and numpy will make a new array with the differences!
import numpy as np
final_array = []
#X is a numpy array that is 30X8100 and Y is a numpy array that is 1X8100
for row in X:
output = row - Y
final_array.append(output)
output will be your resulting array of X[0] - Y, X[1] - Y etc. Now your final_array will be an array with 30 arrays inside, each that have the values of the X-Y that you need! Simple as that. Just make sure you convert your matrices to a numpy arrays first
Edit: Since numpy broadcasting will do the iteration, all you need is one line once you have your two arrays:
final_array = X - Y
And then that is your array with the differences!
a1 = numpy.array(X) #make sure you have a numpy array like [[1,2,3],[4,5,6],...]
a2 = numpy.array(Y) #make sure you have a 1d numpy array like [1,2,3,...]
a2 = [a2] * len(a1[0]) #make a2 as wide as a1
a2 = numpy.array(zip(*a2)) #transpose it (a2 is now same shape as a1)
print a1-a2 #idiomatic difference between a1 and a2 (or X and Y)

Categories