Numpy indexing - Using an unraveled index for basic indexing - python

If I have the following 4D array:
mat = np.array(np.arange(27)).reshape((3,3,3))
[[[ 0 1 2]
[ 3 4 5]
[ 6 7 8]]
[[ 9 10 11]
[12 13 14]
[15 16 17]]
[[18 19 20]
[21 22 23]
[24 25 26]]]
and the following unraveled index:
ind = np.unravel_index([7], mat.shape[1:])
(array([2], dtype=int64), array([1], dtype=int64))
what is the best way to access
mat[:, 2, 1]
[ 7 16 25]
using the unraveled index? I am looking for a generic solution to this issue where the number of dimensions mat has can vary.
I am aware that I could do something like this:
new_ind = (np.arange(mat.shape[0]),) + ind
mat[new_ind]
[ 7 16 25]
but I was wondering if there is way to do this which does not require the explicit construction of a new index?

You do need to construct a new indexing tuple:
In [8]: ind=np.unravel_index([7,8],(3,3))
In [9]: ind
Out[9]: (array([2, 2]), array([1, 2]))
In [10]: (slice(None),*ind)
Out[10]: (slice(None, None, None), array([2, 2]), array([1, 2]))
In [11]: np.arange(27).reshape(3,3,3)[_]
Out[11]:
array([[ 7, 8],
[16, 17],
[25, 26]])
The Out[10] is equivalent to adding a : to your unraveled indices:
In [12]: np.s_[:,[2,2],[1,2]]
Out[12]: (slice(None, None, None), [2, 2], [1, 2])

Related

Indexing numpy array with list of slices

I have a list of slices and use them to index a numpy array.
arr = np.arange(25).reshape(5, 5)
# array([[ 0, 1, 2, 3, 4],
# [ 5, 6, 7, 8, 9],
# [10, 11, 12, 13, 14],
# [15, 16, 17, 18, 19],
# [20, 21, 22, 23, 24]])
slice_list = list(map(lambda i: slice(i, i+2), [1, 2]))
# [slice(1, 3, None), slice(2, 4, None)]
print(arr[slice_list])
# == arr[1:3, 2:4]
# [[ 7 8]
# [12 13]]
This works fine but it breaks if I have fewer slices than the number of dimensions
of the array I want to index.
arr3d = arr[np.newaxis, :, :] # dims: [1, 5, 5]
arr3d[:, slice_list]
# IndexError: only integers, slices (`:`), ellipsis (`...`),(`None`)
# numpy.newaxis and integer or boolean arrays are valid indices
The following examples work however:
arr3d[:, slice_list[0], slice_list[1]]
arr3d[[slice(None)] + slice_list]
arr3d[:, [[1], [2]], [2, 3]]
Is there a way I can use a list of slices to index an array with more dimensions.
I want to do things like:
arr[..., slice_list]
arr[..., slice_list, :]
arr[:, slice_list, :]
without thinking about the dimensions of the array and figuring out how many [slice(None)]*X
I have to pad on either side of my slice_list.
You can do that using tuples of slices and ellipsis objects. Just put all the elements to you want to use for indexing into a tuple and use it as index:
import numpy as np
arr = np.arange(24).reshape(2, 3, 4)
print(arr)
# [[[ 0 1 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]]
#
# [[12 13 14 15]
# [16 17 18 19]
# [20 21 22 23]]]
slice_tup = tuple(map(lambda i: slice(i, i+2), [1, 2]))
print(slice_tup)
# (slice(1, 3, None), slice(2, 4, None))
print(arr[slice_tup])
# [[[20 21 22 23]]]
# arr[..., slice_list]
print(arr[(Ellipsis, *slice_tup)])
# [[[ 6 7]
# [10 11]]
#
# [[18 19]
# [22 23]]]
# arr[..., slice_list, :]
print(arr[(Ellipsis, *slice_tup, slice(None))])
# [[[20 21 22 23]]]
# arr[:, slice_list, :]
print(arr[(slice(None), *slice_tup, slice(None))])
# IndexError: too many indices for array

How to assign new different values to numpy array at the same dimension using iteration function

I have the following multidimensional numpy array:
a = np.arange(16).reshape(2,2,2,2)
I want to assign new different values of the array for each element of certain dimension e.g. 4th dimension
I used the following code:
for i in range(a.shape[3]):
if i == 0:
for t in np.nditer(a[:,:,:,i], op_flags = ['readwrite']):
t[...] = t*2
if i == 1:
for t in np.nditer(a[:,:,:,i], op_flags = ['readwrite']):
t[...] = t*3
print(a)
print(a.shape)
the output is shown as
[[[[ 0 1]
[ 4 3]]
[[ 8 5]
[12 7]]]
[[[16 9]
[20 11]]
[[24 13]
[28 15]]]]
[[[[ 0 3]
[ 4 9]]
[[ 8 15]
[12 21]]]
[[[16 27]
[20 33]]
[[24 39]
[28 45]]]]
(2, 2, 2, 2)
(2, 2, 2, 2)
What I understand that it iterates over the array and at the first i it assigns new values then at the next i it assigns new values and creates new array with both new values besides the first array of the first i that's why I got two arrays in one variable. I only concern about the last array where all values have been assigned the new values. How could I extract the last array only. Or there is another code which is simpler and time saving for this task?
You can simply do this:
>>> a[:,:,:,0] = a[:,:,:,0]*2
>>> a[:,:,:,1] = a[:,:,:,1]*3
>>> a
array([[[[ 0, 3],
[ 4, 9]],
[[ 8, 15],
[12, 21]]],
[[[16, 27],
[20, 33]],
[[24, 39],
[28, 45]]]])
Or even this:
>>> a[:,:,:,0] *= 2
>>> a[:,:,:,1] *= 3

I want to reshape 2D array into 3D array

I want to reshape 2D array into 3D array.I wrote codes,
for i in range(len(array)):
i = np.reshape(i,(2,2,2))
print(i)
i variable has even number's length array like [["100","150","2","4"],["140","120","3","5"]] or
[[“1”,”5”,”6”,”2”],[“4”,”2”,”3”,”7”],[“7”,”5”,”6”,”6”],[“9”,”1”,”8”,”3”],[“3”,”4”,”5”,”6”],[“7”,”8”,”9”,”2”],,[“1”,”5”,”2”,”8”],[“6”,”7”,”2”,”1”],[“9”,”3”,”1”,”2”],[“6”,”8”,”3”,”3”]]
The length is >= 6.
When I run this codes,ValueError: cannot reshape array of size 148 into shape (2,2,2) error happens.
My ideal output is
[[['100', '150'], ['2', '4']], [['140', '120'], ['3', '5']]] or [[[“1”,”5”],[”6”,”2”]],[[“4”,”2”],[”3”,”7”]],[[“7”,”5”],[”6”,”6”]],[[“9”,”1”],[”8”,”3”]],[[“3”,”4”],[”5”,”6”]],[[“7”,”8”],[”9”,”2”]],[[“1”,”5”],[”2”,”8”]],[[“6”,”7”],[”2”,”1”]],[[“9”,”3”],[[”1”,”2”]],[[“6”,”8”],[”3”,”3”]]]
I rewrote the codesy = [[x[:2], x[2:]] for x in i] but output is not my ideal one.What is wrong in my codes?
First of all, you are missing the meaning of reshaping. Let say your origin array has shape (A, B) and you want to reshape it to shape (M, N, O), you have to make sure that A * B = M * N * O. Obviously 148 != 2 * 2 * 2, right?
In your case, you want to reshape an array of shape (N, 4) to an array of shape (N, 2, 2). You can do like below:
x = np.reshape(y, (-1, 2, 2))
Hope this help :)
You don't need to loop to reshape the way you want to, just use arr.reshape((-1,2,2))
In [3]: x = np.random.randint(low=0, high=10, size=(2,4))
In [4]: x
Out[4]:
array([[1, 1, 2, 5],
[8, 8, 0, 5]])
In [5]: x.reshape((-1,2,2))
Out[5]:
array([[[1, 1],
[2, 5]],
[[8, 8],
[0, 5]]])
This approach will work for both of your arrays. The -1 as the first argument means numpy will infer the value of the unknown dimension.
In [76]: arr = np.arange(24).reshape(3,8)
In [77]: for i in range(len(arr)):
...: print(i)
...: i = np.reshape(i, (2,2,2))
...: print(i)
...:
0
....
AttributeError: 'int' object has no attribute 'reshape'
len(arr) is 3, so range(3) produces values, 0,1,2. You can't reshape the number 0.
Or did you mean to reshape arr[0], arr[1], etc?
In [79]: for i in arr:
...: print(i)
...: i = np.reshape(i, (2,2,2))
...: print(i)
...:
[0 1 2 3 4 5 6 7]
[[[0 1]
[2 3]]
[[4 5]
[6 7]]]
[ 8 9 10 11 12 13 14 15]
[[[ 8 9]
[10 11]]
[[12 13]
[14 15]]]
[16 17 18 19 20 21 22 23]
[[[16 17]
[18 19]]
[[20 21]
[22 23]]]
That works - sort of. The prints look ok, but arr itself does not get changed:
In [80]: arr
Out[80]:
array([[ 0, 1, 2, 3, 4, 5, 6, 7],
[ 8, 9, 10, 11, 12, 13, 14, 15],
[16, 17, 18, 19, 20, 21, 22, 23]])
That's because i is the iteration variable. Assigning a new value to it does not change the original object. If that's confusing, you need to review basic Python iteration.
Or we could iterate the range, and use it as an index:
In [81]: for i in range(len(arr)):
...: print(i)
...: x = np.reshape(arr[i], (2,2,2))
...: print(x)
...: arr[i] = x
...:
...:
...:
...:
0
[[[0 1]
[2 3]]
[[4 5]
[6 7]]]
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-81-5f0985cb2277> in <module>()
3 x = np.reshape(arr[i], (2,2,2))
4 print(x)
----> 5 arr[i] = x
6
7
ValueError: could not broadcast input array from shape (2,2,2) into shape (8)
The reshape works, but you can't put a (2,2,2) array back into a slot of shape (8,). The number of elements is right, but the shape isn't.
In other words, you can't reshape an array piecemeal. You have to reshape the whole thing. (If arr was a list of lists, this kind of piecemeal reshaping would work.)
In [82]: np.reshape(arr, (3,2,2,2))
Out[82]:
array([[[[ 0, 1],
[ 2, 3]],
[[ 4, 5],
[ 6, 7]]],
[[[ 8, 9],
[10, 11]],
[[12, 13],
[14, 15]]],
[[[16, 17],
[18, 19]],
[[20, 21],
[22, 23]]]])

can we change the vector into matrix in numpy with the elements in the vector repeats in a matrix with m*n dimensions

import numpy as np
import numba
#numba.vectorize('i4(i4)', target = 'parallel')
def mag(b):
return b * b
def main():
mat_a = np.full((5, 3),2,dtype=np.int32)
c = mag(mat_a)
d = np.sum(c, axis = 1)
print d
OUTPUT: [12 12 12 12 12]
But I want the output to be like this:
[12 12 12]
[12 12 12]
[12 12 12]
[12 12 12]
[12 12 12]
Clear example:
Suppose I have a output like this: [12 13 14 15 16] I want to convert each element in the vector into my own dimensions with numpy
[[12 12 12]
[13 13 13]
[14 14 14]
[15 15 15]
[16 16 16]]
If I understand the question correctly you could simply use np.repeat and reshape:
>>> import numpy as np
>>> arr = np.array([1,2,3,4])
>>> n = 3
>>> np.repeat(arr, n).reshape(-1, arr.size)
array([[1, 1, 1],
[2, 2, 2],
[3, 3, 3],
[4, 4, 4]])
In case the result doesn't need to be writable you could also use np.broadcast_to and transpose:
>>> n = 7
>>> np.broadcast_to(arr, (n, arr.size)).T
array([[1, 1, 1, 1, 1, 1, 1],
[2, 2, 2, 2, 2, 2, 2],
[3, 3, 3, 3, 3, 3, 3],
[4, 4, 4, 4, 4, 4, 4]])

Multiplying NumPy arrays by scalars

I have a NumPy array of shape (2,76020,2). Basically it is made of two columns containing 76020 rows each, and each row has two entries.
I want to multiply each column by a different weight, say column 1 by 3 and column 2 by 5. For example:
m =
[3,4][5,8]
[1,2][2,2]
a = [3,5]
I want:
[9,12][25,40]
[3,6][10,10]
I thought I could just multiply m*a, but that gives me instead:
[9,20][15,40]
[3,10][6,10]
How can I write this multiplication?
It's a problem of broadcasting: you must align the dimensions to multiply, here the second:
m = array(
[[[3,4],[5,8]],
[[1,2],[2,2]]])
a = array([3,5])
print(a[None,:,None].shape, m*a[None,:,None])
"""
(1, 2, 1)
[[[ 9 12]
[25 40]]
[[ 3 6]
[10 10]]]
"""
As #B.M. says, this is a 'array broadcasting' issue. (The idea behind his answer is correct, but I think his and the OP's dimensions aren't matching up correctly.)
>>> m = np.array([[[3,4],[5,8]],[[1,2],[2,2]]])
>>> print(m)
[[[3 4]
[5 8]]
[[1 2]
[2 2]]]
>>> print(m.shape)
(2, 2, 2)
>>> a = np.array([3,5])
>>> print(a.shape)
(2,)
We need the shapes of m and a to match, so we have to 'broadcast' a to the correct shape:
>>> print(a[:, np.newaxis, np.newaxis].shape)
(2, 1, 1)
>>> b = a[:, np.newaxis, np.newaxis] * m
>>> print(b)
[[[ 9 12]
[15 24]]
[[ 5 10]
[10 10]]]
In this way the first dimension of a is preserved, and maps to each element of the first dimension of m. But there are also two new dimensions ('axes') created to 'broadcast' into the other two dimensions of m.
Note: np.newaxis is (literally) None, they have the same effect. The former is more readable to understand what's happening. Additionally, just in terms of standard terminology, the first dimension (axis) is generally referred to as the 'rows', and the second axis the 'columns'.
Your description is ambiguous
Basically it is made of two columns containing 76020 rows each, and each row has two entries.
In (2,76020,2), which 2 is columns, and which is entries?
I believe your m is (that display is also ambiguous)
In [8]: m
Out[8]:
array([[[3, 4],
[5, 8]],
[[1, 2],
[2, 2]]])
In [9]: m*a
Out[9]:
array([[[ 9, 20],
[15, 40]],
[[ 3, 10],
[ 6, 10]]])
That's the same as m*a[None,None,:]. When broadcasting, numpy automatically adds dimensions at the beginning as needed. Or iteratively:
In [6]: m[:,:,0]*3
Out[6]:
array([[ 9, 15],
[ 3, 6]])
In [7]: m[:,:,1]*5
Out[7]:
array([[20, 40],
[10, 10]])
Since m is (2,2,2) shape, we can't off hand tell which axis a is supposed to multiply.
According to the accepted answer, you want to multiply along the middle axis
In [16]: m*a[None,:,None]
Out[16]:
array([[[ 9, 12],
[25, 40]],
[[ 3, 6],
[10, 10]]])
But what if m was (2,3,2) in shape? a would then have to have 3 values
In [17]: m=np.array([[[3,4],[5,8],[0,0]],[[1,2],[2,2],[1,1]]])
In [18]: m*a[None,:,None]
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-18-f631c33646b7> in <module>()
----> 1 m*a[None,:,None]
ValueError: operands could not be broadcast together with shapes (2,3,2) (1,2,1)
The alternative broadcastings work
In [19]: m*a[:,None,None]
Out[19]:
array([[[ 9, 12],
[15, 24],
[ 0, 0]],
[[ 5, 10],
[10, 10],
[ 5, 5]]])
In [20]: m*a[None,None,:]
Out[20]:
array([[[ 9, 20],
[15, 40],
[ 0, 0]],
[[ 3, 10],
[ 6, 10],
[ 3, 5]]])
Now if m had distinct dimensions, e.g. (3,1000,2), we could tell at a glance with axis a 2 element weight array would work with.

Categories