Get elements from a numpy array using another array - python

I have a numpy array, a, of shape (2, 5, 2). I need to get 2 elements from the array at locations [0, 1, 0] and [1, 3, 0]. To retrieve these elements, I have an array, b, with entries [1, 3]. When I use a[:,b], I get 2x2 matrix (as expected). How can I change the indexing to return the required vector instead? Following is an MWE.
import numpy as np
a = np.random.randn(2, 5, 2)
b = np.random.randint(0, 5, 2)
c = a[:, b]
c.shape # prints (2, 2), while I only need a[0, b[0]] and a[1, b[1]].
PS: This problem can be solved using a for loop. However in my actual code the index is in the order of 1000 and therefore not feasible.

As pointed out in the comments, one can do c = a[np.arange(a.shape[0]), b] to obtain the required result.

Related

How to concatenate sliced array to a list in Python

I am trying to merge a sliced array to a list in Python but i get an
error: ValueError: operands could not be broadcast together with shapes `(4,)` `(2,)` .
This is my code:
y = np.array([5,3,2,4,6,1])
row = y[2:6] + np.array([0,0])
I am expecting to get a 2-item shifted vector to the left and last 2 items being assigned to 0.
Numpy array works something like a matrix. So when you try to apply the addition operation to a numpy array, you're actually performing an "element-wise addition". That's why the value you add with a numpy array must be the same dimension as the numpy array. Otherwise such a value that can be broadcasted.
Notice the example to understand what I'm saying.
Adding two lists with addition sign:
>>> [1,2] + [3,4]
[1, 2, 3, 4]
Adding two numpy arrays:
>>> np.array([1,2]) + np.array([3,4])
array([4, 6])
To get your work done, use the np.append(arr, val, axis) function. Documentation
array([1, 2, 3, 4])
>>> np.append([1,2], np.array([3,4]))
array([1, 2, 3, 4])
To concatenate arrays use np.concatenate:
In [93]: y = np.array([5,3,2,4,6,1])
In [94]: y[2:6]
Out[94]: array([2, 4, 6, 1])
In [95]: np.concatenate((y[2:6], np.array([0,0])))
Out[95]: array([2, 4, 6, 1, 0, 0])
+ is concatenate for lists. For arrays is addition (numeric sum).
Your question should not have used list and array in a sloppy manner. They are different things (in python/numpy) and can produce confusing answers.
Other answers already explain why your code fail. You can do:
out = np.zeros_like(y)
out[:-2] = y[2:]
Output:
array([2, 4, 6, 1, 0, 0])
For concatenation, you will need to convert your numpy array to a list first.
row = y[2:6] + list(np.array([0,0]))
or equivalently
row = y[2:6] + np.array([0,0]).tolist()
However, if you wish to add the two (superpose a list and numpy array), then the numpy array just needs to be the same shape as y[2:6]:
In : y[2:6] + np.array([1, 2, 3, 4])
Out: array([y[2] + 1, y[3] + 2, y[4] + 3, y[5] + 4])

Getting the indices of several elements in a NumPy array (can be repeated) at once

Is there any way to get the indices of several elements in a NumPy array at once?
For example:
import numpy as np
a = np.array([1, 2, 4])
b = np.array([1, 1, 3, 2, 4])
I would like to find the index of each element of a in b, namely: [0, 1, 3, 4].
Please Note:
b has duplicated values, e.g. 1 here, methods for example in Getting the indices of several elements in a NumPy array at once would not work because it only find left-most or right-most index, not all indices. So using the method there would get [0, 3, 4] if left-most applied.
I want to honour the order of the values in a, i.e. the first digits in the result is for the first value in a, and second few digits are for second value in a and so on, e.g. [0, 1] is for 1 in a, [3] is for 2 in a, and [4] is for 4 in a, so order in answer is [0, 1, 3, 4]
Thanks to my friend #rongkaizhang, I posted his beautiful answer here.
np.where(b == np.expand_dims(a, axis=1))[1]

Does 1-dimensional numpy array always behave like a row vector?

I am trying to get a good understanding on broadcasting rules in numpy, but I have noticed I firstly need to get a good understanding on what 1-dimensional numpy array is. I found multiple sources saying that 1-dimensional numpy array is neither a horizontal or vertical vector. From that I'd expect that it behaves differently depending on an operation done and other component of the operation. But I can't really find a case when 1-dimensional array would behave like a column vector. For example:
a = np.arange(3)
b = np.arange(3)[:, np.newaxis]
a + b
array([[0, 1, 2],
[1, 2, 3],
[2, 3, 4]])
which indicates that a behaves like a horizontal vector. On the other hand, if we add it to horizontal vector b:
a = np.arange(3)
b = np.arange(3)[np.newaxis, :]
a + b
array([[0, 1, 4]])
a still behaves like a horizontal vector. On the other hand a seems to be indifferent to transformation with .T. So my question is - does 1-dimensional numpy arrays always mimic the horizontal vector behaviour? If not, what are the cases when they behave like standard vertical vector?
What you just came across is known as right align property of numpy arrays. When you have a vector of shape (n, ) and some other array of shape (a, b, c, d, ..., z) then numpy will always try to broadcast the vector to shape (1, 1, ...., n) and finally check if n is broadcastable with z (in other words, z is a multiple of n).
Now, if you don't want the behaviour, you will have to tell numpy explicitly, how do you want to broadcast with the other array with which you are operating by adding axis to the vector using np.newaxis. You can also use the function np.broadcast_arrays to get the broadcasted arrays.
For example,
import numpy as np
a = np.array([1, 2, 3])
b = np.eye(3)
# broadcasts a to shape (1, 3) first
# adds the vector a to rows of b
# [[1, 0, 0] [[1, 2, 3]
# [0, 1, 0] + [1, 2, 3]
# [0, 0, 1]] [1, 2, 3]]
print(a + b)
# Tell numpy explicitly, how you want
# your vector to be broadcasted
# Now, a is first broadcasted to shape (3, 1)
# and the vector a is added to the columns of b
# [[1, 0, 0] [[1, 1, 1]
# [0, 1, 0] + [2, 2, 2]
# [0, 0, 1]] [3, 3, 3]]
print(b + a[np.newaxis, :])

What is happening in this numpy problem where a numpy array is multiplied with different array?

import numpy as np
x = np.array([[1, 2], [3, 4], [5, 6]])
y = x [[0,1,2], [0,1,0]] #:i did not understand this step,what is happening here?
print y
OUTPUT: [1 4 5]
When you're doing
x[a, b]
With a and b being arrays, you're specifying a series of indices to use. For instance, here you are saying "pick the 0th row, then the 1st, then the 2nd" and "pick the 0th column, the 1st and the 0th".
So, your resulting array is [x[0,0], x[1,1], x[2,0]]
This operation provides the sequence of the values with indexes taken from [0,1,2], [0,1,0]. First list relates to the first dimension, second one to the second one. So the coordinates will be (0, 0), (1, 1), (2, 0) and its values are 1, 4, 5 in the array x.

How does the axis parameter from NumPy work?

Can someone explain exactly what the axis parameter in NumPy does?
I am terribly confused.
I'm trying to use the function myArray.sum(axis=num)
At first I thought if the array is itself 3 dimensions, axis=0 will return three elements, consisting of the sum of all nested items in that same position. If each dimension contained five dimensions, I expected axis=1 to return a result of five items, and so on.
However this is not the case, and the documentation does not do a good job helping me out (they use a 3x3x3 array so it's hard to tell what's happening)
Here's what I did:
>>> e
array([[[1, 0],
[0, 0]],
[[1, 1],
[1, 0]],
[[1, 0],
[0, 1]]])
>>> e.sum(axis = 0)
array([[3, 1],
[1, 1]])
>>> e.sum(axis=1)
array([[1, 0],
[2, 1],
[1, 1]])
>>> e.sum(axis=2)
array([[1, 0],
[2, 1],
[1, 1]])
>>>
Clearly the result is not intuitive.
Clearly,
e.shape == (3, 2, 2)
Sum over an axis is a reduction operation so the specified axis disappears. Hence,
e.sum(axis=0).shape == (2, 2)
e.sum(axis=1).shape == (3, 2)
e.sum(axis=2).shape == (3, 2)
Intuitively, we are "squashing" the array along the chosen axis, and summing the numbers that get squashed together.
To understand the axis intuitively, refer the picture below (source: Physics Dept, Cornell Uni)
The shape of the (boolean) array in the above figure is shape=(8, 3). ndarray.shape will return a tuple where the entries correspond to the length of the particular dimension. In our example, 8 corresponds to length of axis 0 whereas 3 corresponds to length of axis 1.
If someone need this visual description:
There are good answers for visualization however it might help to think purely from analytical perspective.
You can create array of arbitrary dimension with numpy.
For example, here's a 5-dimension array:
>>> a = np.random.rand(2, 3, 4, 5, 6)
>>> a.shape
(2, 3, 4, 5, 6)
You can access any element of this array by specifying indices. For example, here's the first element of this array:
>>> a[0, 0, 0, 0, 0]
0.0038908603263844155
Now if you take out one of the dimensions, you get number of elements in that dimension:
>>> a[0, 0, :, 0, 0]
array([0.00389086, 0.27394775, 0.26565889, 0.62125279])
When you apply a function like sum with axis parameter, that dimension gets eliminated and array of dimension less than original gets created. For each cell in new array, the operator will get list of elements and apply the reduction function to get a scaler.
>>> np.sum(a, axis=2).shape
(2, 3, 5, 6)
Now you can check that the first element of this array is sum of above elements:
>>> np.sum(a, axis=2)[0, 0, 0, 0]
1.1647502999560164
>>> a[0, 0, :, 0, 0].sum()
1.1647502999560164
The axis=None has special meaning to flatten out the array and apply function on all numbers.
Now you can think about more complex cases where axis is not just number but a tuple:
>>> np.sum(a, axis=(2,3)).shape
(2, 3, 6)
Note that we use same technique to figure out how this reduction was done:
>>> np.sum(a, axis=(2,3))[0,0,0]
7.889432081931909
>>> a[0, 0, :, :, 0].sum()
7.88943208193191
You can also use same reasoning for adding dimension in array instead of reducing dimension:
>>> x = np.random.rand(3, 4)
>>> y = np.random.rand(3, 4)
# New dimension is created on specified axis
>>> np.stack([x, y], axis=2).shape
(3, 4, 2)
>>> np.stack([x, y], axis=0).shape
(2, 3, 4)
# To retrieve item i in stack set i in that axis
Hope this gives you generic and full understanding of this important parameter.
Some answers are too specific or do not address the main source of confusion. This answer attempts to provide a more general but simple explanation of the concept, with a simple example.
The main source of confusion is related to expressions such as "Axis along which the means are computed", which is the documentation of the argument axis of the numpy.mean function. What the heck does "along which" even mean here? "Along which" essentially means that you will sum the rows (and divide by the number of rows, given that we are computing the mean), if the axis is 0, and the columns, if the axis is 1. In the case of axis is 0 (or 1), the rows can be scalars or vectors or even other multi-dimensional arrays.
In [1]: import numpy as np
In [2]: a=np.array([[1, 2], [3, 4]])
In [3]: a
Out[3]:
array([[1, 2],
[3, 4]])
In [4]: np.mean(a, axis=0)
Out[4]: array([2., 3.])
In [5]: np.mean(a, axis=1)
Out[5]: array([1.5, 3.5])
So, in the example above, np.mean(a, axis=0) returns array([2., 3.]) because (1 + 3)/2 = 2 and (2 + 4)/2 = 3. It returns an array of two numbers because it returns the mean of the rows for each column (and there are two columns).
Both 1st and 2nd reply is great for understanding ndarray concept in numpy. I am giving a simple example.
And according to this image by #debaonline4u
https://i.stack.imgur.com/O5hBF.jpg
Suppose , you have an 2D array -
[1, 2, 3]
[4, 5, 6]
In, numpy format it will be -
c = np.array([[1, 2, 3],
[4, 5, 6]])
Now,
c.ndim = 2 (rows/axis=0)
c.shape = (2,3) (axis0, axis1)
c.sum(axis=0) = [1+4, 2+5, 3+6] = [5, 7, 9] (sum of the 1st elements of each rows, so along axis0)
c.sum(axis=1) = [1+2+3, 4+5+6] = [6, 15] (sum of the elements in a row, so along axis1)
So for your 3D array,

Categories