How does np.multiply work? - python

I am trying to implement np.multiply in Java and I am confused about what it is actually doing. The documentation simply states it does element-wise multiplication. It does not match any mathematical matrix product I can find. It partially matches the element-wise Hadamard product but doesn't need the same number of rows and columns. Does anyone know what mathematical product np.multiply performs and have any more information into EXACTLY how it is working?
Here are the different outputs I've been getting. These seem like very different functionality.
a = np.array([[1,1,1],[2,2,2],[2,3]])
b = np.array([[2,3,4]])
print(np.multiply(a,b))
#output
[[1, 1, 1, 1, 1, 1] [2, 2, 2, 2, 2, 2, 2, 2, 2] [2, 3, 2, 3, 2, 3, 2, 3]]]
and
a = np.array([[1,1,1],[2,2,2]])
b = np.array([[2,3,4]])
print(np.multiply(a,b))
#output
[[2 3 4]
[4 6 8]]

It's doing elementwise multiplication just like the documentation says. note, in your first example,
a = np.array([[1,1,1],[2,2,2],[2,3]])
b = np.array([[2,3,4]])
You have an array of objects (lists) because all of the sub-lists don't have the same length.
>>> a = np.array([[1,1,1],[2,2,2],[2,3]])
>>> a
array([[1, 1, 1], [2, 2, 2], [2, 3]], dtype=object)
So when you multiply them, you're multiplying a list by an integer -- which what you got in the result.
e.g. if c = np.multiply(a, b), then:
c[0] == [1, 1, 1] * 2
c[1] == [2, 2, 2] * 3
c[2] == [2, 3] * 4
So far, we see that multiplying arrays of the same shape produces the Handamard product. What about when they aren't the same shape? In the case, numpy tries to "broadcast" them to the same shape. The rules can be somewhat complex, so I won't try to reproduce them here, but they can be found at http://docs.scipy.org/doc/numpy-1.10.1/user/basics.broadcasting.html. Scalar-array multiplication works the same as scalar-matrix multiplication works in mathematics. For arrays which aren't the same shape, the trailing dimensions must match and the array with fewer dimensions is repeated as many times as necessary to fill out the missing dimensions and then the Handamard product is performed.
e.g.
a = np.array([[1, 2, 3], [1, 2, 3]])
b = np.array([3, 2, 1])
c = np.array([[3, 2, 1], [3, 2, 1]])
In this case, a * b and a * c will give the same result.
Obviously, the way I'm describing it isn't the way it's implemented (that would be seriously inefficient), but it helps as a way of thinking about it.

Related

Numpy: Compute dot product of 2d arrays with a condition before summation

I have a problem where I have two arrays with dimensions
n x d and d x h, where n, d, and h are positive integers that may or may not be the same. I am trying to find the dot product of the two matrices but with the condition that for each multiplication, I apply a function g to the term.
For example, in a case where n=2, d=3, and h=3
If I had the following matrices:
a = [[1, 2, 3],
[4, 5, 6]]
b = [[1, 2, 3],
[4, 5, 6],
[1, 1, 1]]
I would want to find c such that
c = [[g(1*1)+g(2*4)+g(3*1), g(1*2)+g(2*5)+g(3*1), g(1*3)+g(2*6)+g(3*1)],
[g(4*1)+g(5*4)+g(6*1), g(4*2)+g(5*5)+g(6*1), g(4*3)+g(5*6)+g(6*1)]]
Any help would be appreciated
I was able to do this by first doing the multiplications with broadcasting, applying g(), and then summing across the correct axis:
import numpy as np
def g(x):
return 1 / (1 + np.exp(-x))
a = np.array([[1, 2, 3],
[4, 5, 6]])
b = np.array([[1, 2, 3],
[4, 5, 6],
[1, 1, 1]])
First, the multiplication a[:, None] * b.T (probably a nicer way to do this), then evaluate g(x), then sum across axis 2:
>>> g(a[:, None] * b.T).sum(axis=2)
array([[2.68329736, 2.83332581, 2.90514211],
[2.97954116, 2.99719203, 2.99752123]])
Verifying that the first row indeed matches your desired result:
>>> g(1*1) + g(2*4) + g(3*1)
2.683297355321972
>>> g(1*2) + g(2*5) + g(3*1)
2.8333258069316134
>>> g(1*3) + g(2*6) + g(3*1)
2.9051421094702645

Add 2D arrays side by side in python

Hello everyone I want to add 2 2x2 arrays side by side in python. In the end I want to get a 2x4 array which rows are shared and 1st and 2nd columns are from the first array and 3rd and the 4th columns are from the second array. I get an array where it sums the arrays not put them side by side. Can you help me please?
Example:
Array 1:
[[1 2]
[1 2]]
Array 2:
[[1 2]
[1 2]]
Expected Result:
[[1 2 1 2]
[1 2 1 2]]
Real Result:
[[2 4]
[2 4]]
import numpy as np
a = np.matrix('1 2; 1 2')
b = np.matrix('1 2; 1 2')
x = a + b
print(x)
Using np.concatenate
>>> numpy.concatenate((a, b), axis=1)
matrix([[1, 2, 1, 2],
[1, 2, 1, 2]])
Another option is using np.hstack:
>>> np.hstack((a, b))
matrix([[1, 2, 1, 2],
[1, 2, 1, 2]])
The reason I think why this is happening is because the addition returns a normal matrix addition that adds the two matrices component by component.
Try, np.concatenate(), it might help as #sacul has suggested.
numpy arrays do not act in the same way as python lists. Whereas the + operator can do some sort of list concatenation, when you use it with numpy arrays, you are doing vector addition.
Instead, you can flatten each array and concatenate:
np.concatenate([a.flatten(),b.flatten()])
matrix([[1, 2, 1, 2],
[1, 2, 1, 2]])
[Edit:]
re-reading your question, it seems I misunderstood what you were after. #Thomas' answers make more sense in your scenario, and an alternative would be np.column_stack:
>>> np.column_stack((a,b))
matrix([[1, 2, 1, 2],
[1, 2, 1, 2]])

numpy: how to construct a matrix of vectors from vector of matrix

I'm new to numpy,
so, with numpy, is it possible to use a vector of matrix to get a matrix of vectors"
for example:
matrix1(
[
[1, 2, 3],
[1, 2, 3],
[1, 2, 3]
])
matrix2(
[
[2, 4, 6],
[2, 4, 6],
[2, 4, 6]
])
-->
matrix(
[
[array('1 2'), array('2 4'), array('3 6')],
[array('1 2'), array('2 4'), array('3 6')],
[array('1 2'), array('2 4'), array('3 6')]
])
I'm new to numpy, so I'm not sure if it is allowed to put any thing in numpy's matrix or just numbers.
And it's not easy to get answer from google with descriptions like "matrix of vectors and vectors of matrix"
numpy doesn't have a concept of "vector" separate from "matrix." It does have distinct concepts of "matrix" and "array," but most people avoid the matrix representation entirely. If you use arrays, the concepts of "vector," "matrix," and "tensor" are all subsumed under the general concept of an array's "shape" attribute.
In this worldview, vectors and matrices are both 2-dimensional arrays, distinguished only by their shape. Row vectors are arrays with the shape (1, n), while column vectors are arrays with the shape (n, 1). Matrices are arrays with the shape (n, m). 1-dimensional arrays can behave like vectors sometimes, depending on context, but often you'll find that you won't get what you want unless you "upgrade" them.
With all that in mind, here's one possible answer to your question. First, we create a 1-d array:
>>> a1d = numpy.array([1, 2, 3])
>>> a1d
array([1, 2, 3])
Now we reshape it to create a column vector. The -1 here tells numpy to figure out the right size given the input.
>>> vcol = a1d.reshape((-1, 1))
>>> vcol
array([[1],
[2],
[3]])
Observe the doubled brackets at the beginning and ending of this. That's a subtle cue that this is a 2-d array, even though one dimension has a size of just 1.
We can do the same thing, swapping the dimensions, to get a row. Note again the doubled brackets.
>>> vrow = a1d.reshape((1, -1))
>>> vrow
array([[1, 2, 3]])
You can tell that these are 2-d arrays, because a 1-d array would have only one value in its shape tuple:
>>> a1d.shape
(3,)
>>> vcol.shape
(3, 1)
>>> vrow.shape
(1, 3)
To build a matrix from column vectors we can use hstack. There are lots of other methods that may be faster, but this is a good starting point. Here, note that [vcol] is not a numpy object, but an ordinary python list, so [vcol] * 3 means the same thing as [vcol, vcol, vcol].
>>> mat = numpy.hstack([vcol] * 3)
>>> mat
array([[1, 1, 1],
[2, 2, 2],
[3, 3, 3]])
And vstack gives us the same thing from row vectors.
>>> mat2 = numpy.vstack([vrow] * 3)
>>> mat2
array([[1, 2, 3],
[1, 2, 3],
[1, 2, 3]])
It's unlikely that any other interpretation of "construct a matrix of vectors from vector of matrix" will generate something you actually want in numpy!
Since you mention wanting to do linear algebra, here are a couple of operations that are possible. This assumes you're using a recent-enough version of python to use the new # operator, which provides an unambiguous inline notation for matrix multiplication of arrays.1
For arrays, multiplication is always element-wise. But sometimes there is broadcasting. For values with the same shape, it's plain element-wise multiplication:
>>> vrow * vrow
array([[1, 4, 9]])
>>> vcol * vcol
array([[1],
[4],
[9]])
When values have different shapes, they are broadcast together if possible to produce a sensible result:
>>> vrow * vcol
array([[1, 2, 3],
[2, 4, 6],
[3, 6, 9]])
>>> vcol * vrow
array([[1, 2, 3],
[2, 4, 6],
[3, 6, 9]])
Broadcasting works in the way you'd expect for other shapes as well:
>>> vrow * mat
array([[1, 2, 3],
[2, 4, 6],
[3, 6, 9]])
>>> vcol * mat
array([[1, 1, 1],
[4, 4, 4],
[9, 9, 9]])
If you want a dot product, you have to use the # operator:
>>> vrow # vcol
array([[14]])
Note that unlike the * operator, this is not symmetric:
>>> vcol # vrow
array([[1, 2, 3],
[2, 4, 6],
[3, 6, 9]])
This can be a bit confusing at first, because this looks the same as vrow * vcol, but don't be fooled. * will produce the same result regardless of argument order. Finally, for a matrix-vector product:
>>> mat # vcol
array([[ 6],
[12],
[18]])
Observe again the difference between # and *:
>>> mat * vcol
array([[1, 1, 1],
[4, 4, 4],
[9, 9, 9]])
1. Sadly, this only exists as of Python 3.5. If you need to work with an earlier version, all the same advice applies, except that instead of using inline notation for a # b, you have to use np.dot(a, b). numpy's matrix type overrides * to behave like #... but then you can't do element-wise multiplication or broadcasting the same way! So even if you have an earlier version, I don't recommend using the matrix type.

Replace value in an array by its index in a list

In a given array I want to replace the values by the index of this value in an other array (which doesn't contain duplicates). Here is a simple example of I'm trying to do:
import numpy as np
from copy import deepcopy
a = np.array([[0, 1, 2], [2, 1, 3], [0, 1, 3]])
chg = np.array([3, 0, 2, 1])
b = deepcopy(a)
for new, old in enumerate(chg):
b[a == old] = new
print b
# [[1 3 2] [2 3 0] [1 3 0]]
But I need to do that on large arrays so having an explicit loop is not acceptable in terms of execution time.
I can't figure out how to do that using fancy numpy functions...
take is your friend.
a = np.array([[0, 1, 2], [2, 1, 3], [0, 1, 3]])
chg = np.array([3, 0, 2, 1])
inverse_chg=chg.take(chg)
print(inverse_chg.take(a))
gives :
[[1 3 2]
[2 3 0]
[1 3 0]]
or more directly with fancy indexing: chg[chg][a], but inverse_chg.take(a) is three times faster.
You can convert chg to a 3D array by adding two new axes at the end of it and then perform the matching comparison with a, which would bring in NumPy's broadcasting to give us a 3D mask. Next up, get the argmax on the mask along the first axis to simulate "b[a == old] = new". Finally, replace the ones that had no matches along that axis with the corresponding values in a. The implementation would look something like this -
mask = a == chg[:,None,None]
out = mask.argmax(0)
invalid_pos = ~mask.max(0)
out[invalid_pos] = a[invalid_pos]
This type of replacement operation can be tricky to do in full generality with NumPy, although you could use searchsorted:
>>> s = np.argsort(chg)
>>> s[np.searchsorted(chg, a.ravel(), sorter=s).reshape(a.shape)]
array([[1, 3, 2],
[2, 3, 0],
[1, 3, 0]])
(Note: searchsorted doesn't just replace exact matches, so be careful if you have values in a that aren't in chg...)
pandas has a variety of tools which can make these operations on NumPy arrays much easier and potentially a lot quicker / more memory efficient for larger arrays. For this specific problem, pd.match could be used:
>>> pd.match(a.ravel(), chg).reshape(a.shape)
array([[1, 3, 2],
[2, 3, 0],
[1, 3, 0]])
This function also allows you to specify what value should be filled if a value is missing from chg.
Check this out:
a = np.array([3,4,1,2,0])
b = np.array([[0,0],[0,1],[0,2],[0,3],[0,4]])
c = b[a]
print(c)
It gives me back:
[[0 3]
[0 4]
[0 1]
[0 2]
[0 0]]
If you're working with numpy arrays you could do this.

NumPy min/max in-place assignment

Is it possible to perform min/max in-place assignment with NumPy multi-dimensional arrays without an extra copy?
Say, a and b are two 2D numpy arrays and I would like to have a[i,j] = min(a[i,j], b[i,j]) for all i and j.
One way to do this is:
a = numpy.minimum(a, b)
But according to the documentation, numpy.minimum creates and returns a new array:
numpy.minimum(x1, x2[, out])
Element-wise minimum of array elements.
Compare two arrays and returns a new array containing the element-wise minima.
So in the code above, it will create a new temporary array (min of a and b), then assign it to a and dispose it, right?
Is there any way to do something like a.min_with(b) so that the min-result is assigned back to a in-place?
numpy.minimum() takes an optional third argument, which is the output array. You can specify a there to have it modified in place:
In [9]: a = np.array([[1, 2, 3], [2, 2, 2], [3, 2, 1]])
In [10]: b = np.array([[3, 2, 1], [1, 2, 1], [1, 2, 1]])
In [11]: np.minimum(a, b, a)
Out[11]:
array([[1, 2, 1],
[1, 2, 1],
[1, 2, 1]])
In [12]: a
Out[12]:
array([[1, 2, 1],
[1, 2, 1],
[1, 2, 1]])

Categories