How to index multi-dimensional array with another array? - python

Let's consider a multi-dimensional array
arr = np.zeros((3,2,4))
and some indexing array
index_arr = np.array([2, 1])
To clarify what I want to get, it's this (but I want to provide indices dynamically):
arr[2, 1] # array([0., 0., 0., 0.])
NOT this:
arr[[2, 1]] # which returns result with shape (2, 2, 4)
I would have liked to do something like this
arr[*index_arr] # using * to unpack the items of `index_arr`
but that gives a syntax error. Is there a native way to do what I'm asking for?

Related

How to index single element in ndarray using list?

I'm starting to learn numpy and can't understand the very basic thing. I have a list of indexes
in a multidimensional array (one for each axis). How can I set the value to the point in an array that corresponds to that index? Basically, how can I use idxs variable in the folllowing code and produce same result?
A = np.zeros((2, 2))
idxs = [1, 0]
A[1, 0] = 1
A
array([[0., 0.],
[1., 0.]])
Thanks to Ivan,
A[tuple(idxs)] = 1
works

Add a level to Numpy array

I have a problem with a numpy array.
In particular, suppose to have a matrix
x = np.array([[1., 2., 3.], [4., 5., 6.]])
with shape (2,3), I want to convert the float numbers into list so to obtain the array [[[1.], [2.], [3.]], [[4.], [5.], [6.]]] with shape (2,3,1).
I tried to convert each float number to a list (i.e., x[0][0] = [x[0][0]]) but it does not work.
Can anyone help me? Thanks
What you want is adding another dimension to your numpy array. One way of doing it is using reshape:
x = x.reshape(2,3,1)
output:
[[[1.]
[2.]
[3.]]
[[4.]
[5.]
[6.]]]
There is a function in Numpy to perform exactly what #Valdi_Bo mentions. You can use np.expand_dims and add a new dimension along axis 2, as follows:
x = np.expand_dims(x, axis=2)
Refer:
np.expand_dims
Actually, you want to add a dimension (not level).
To do it, run:
result = x[...,np.newaxis]
Its shape is just (2, 3, 1).
Or save the result back under x.
You are trying to add a new dimension to the numpy array. There are multiple ways of doing this as other answers mentioned np.expand_dims, np.new_axis, np.reshape etc. But I usually use the following as I find it the most readable, especially when you are working with vectorizing multiple tensors and complex operations involving broadcasting (check this Bounty question that I solved with this method).
x[:,:,None].shape
(2,3,1)
x[None,:,None,:,None].shape
(1,2,1,3,1)
Well, maybe this is an overkill for the array you have, but definitely the most efficient solution is to use np.lib.stride_tricks.as_strided. This way no data is copied.
import numpy as np
x = np.array([[1., 2., 3.], [4., 5., 6.]])
newshape = x.shape[:-1] + (x.shape[-1], 1)
newstrides = x.strides + x.strides[-1:]
a = np.lib.stride_tricks.as_strided(x, shape=newshape, strides=newstrides)
results in:
array([[[1.],
[2.],
[3.]],
[[4.],
[5.],
[6.]]])
>>> a.shape
(2, 3, 1)

turn list of python arrays into an array of python lists

I have a list of python arrays like the following:
[array([[0., 0., 0.]]),
array([[0., 0., 0.]]),
array([[0., 0., 0.]])]
My goal is to change them to an array of lists like the following:
array([[ 0, 0, 0],
[ 0, 0, 0],
[ 0, 0, 0]])
I tried the following however I'm getting I'm an error:
np.array([my_array[i].tolist() for i in my_array])
The following is the error:
TypeError: only integer scalar arrays can be converted to a scalar index
Could anyone help me understand what's going and what I'm doing wrong.
You can just concatenate row-wise with vstack since they are of shape (1, 3) in your example to get the result of shape (n, 3).
np.vstack(my_array)
Why your current code fails is because you are iterating over every sub-array in my_array and trying to index my_array with that. So you are indexing a list with array([[0., 0., 0.]]) which is not a scaler index because it is an array.
Alternative options:
np.array(my_array).reshape(-1, 3)
np.array([e.reshape(-1) for e in my_array])
...
Try:
np.array([i[0] for i in my_array])
Since in your case, i is not the index of a, it represents each element in my_array
And each of your element in my_array is a nested list, you may want to flat the nested list when doing the conversion

build numpy array from list of tuples

I want to convert a list of tuples into a numpy array. For example:
items = [(1, 2), (3, 4)]
using np.asarray(items) I get:
array([[1, 2],
[3, 4]])
but if I try to append the items individually:
new_array = np.empty(0)
for item in items:
new_array = np.append(new_array, item)
the new_array loses the original shape and becomes:
array([1., 2., 3., 4.])
I can get it to the shape I wanted using new_array.reshape(2, 2):
array([[1., 2.],
[3., 4.]])
but how would I get that shape without reshaping?
Firstly you need to provide a correct shape to the array so that numpy could understand how to interpret the values provided to the append method.
Then, to prevent automatic flattening, specify the axis you wish to append on.
This code does what you intended to do:
import numpy as np
items = [(1,2),(3,4)]
new_array = np.ndarray((0,2))
for item in items:
new_array = np.append(new_array, [item], axis=0)
print(new_array) # [[1. 2.]
# [3. 4.]]
If you have a list of tuples, and you've decided you hate the standard array constructors (np.array, np.asarray, etc, which, as #JohnZwinck pointed out are probably the best answer) for some reason, the most efficient approach would be to preallocate the entire array and then assign to it:
items = [(1, 2), (3, 4)]
arr = np.empty((len(items), len(items[0])))
arr[...] = items
Even if what you want is to grow an array over time, row-by-row, it has been shown through detailed timings that you're usually better off just allocating a whole new array and then copying over the old values.
So given the above arr, by this approach the most efficient way to append a row would be:
newitem = (5, 6)
oldarr = arr
arr = np.empty((oldarr.shape[0] + 1, *oldarr.shape[1:]))
arr[:-1,:] = oldarr
arr[-1,:] = newitem

Indexing with ndarray in the same way as using tuples

I'd like to index my 2d-array using a 1d-array of size two in the same way a tuple or basic indexing would be used. I have the indices as np.ndarrays for convenience when it comes to manipulations, but currently I'm converting them back and forth to tuples.
a = np.zeros((5, 5))
ix = np.array([3, 2])
>>> a[3, 2]
0.0
>>> a[(3, 2)]
0.0
>>> a[ix]
array([[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.]])
I've tried it with reshaping the array a bunch of ways, e.g. shapes (2, 1) and (1, 2), but no luck. Also couldn't find an entry from the documentation.
Is there a way?
Pass ix as a tuple for indexing, not an array/list, since the latter will specify a selection of rows, rather than a single cell.
So either a[tuple(ix)] or a[(*ix,)] will work.

Categories