If I have a multidimensional array like this:
a = np.array([[9,9,9],[9,0,9],[9,9,9]])
I'd like to get an array of each index in that array, like so:
i = np.array([[0,0],[0,1],[0,2],[1,0],[1,1],...])
One way of doing this that I've found is like this, using np.indices:
i = np.transpose(np.indices(a.shape)).reshape(a.shape[0] * a.shape[1], 2)
But that seems somewhat clumsy, especially given the presence of np.nonzero which almost does what I want.
Is there a built-in numpy function that will produce an array of the indices of every item in a 2D numpy array?
Here is one more concise way (if the order is not important):
In [56]: np.indices(a.shape).T.reshape(a.size, 2)
Out[56]:
array([[0, 0],
[1, 0],
[2, 0],
[0, 1],
[1, 1],
[2, 1],
[0, 2],
[1, 2],
[2, 2]])
If you want it in your intended order you can use dstack:
In [46]: np.dstack(np.indices(a.shape)).reshape(a.size, 2)
Out[46]:
array([[0, 0],
[0, 1],
[0, 2],
[1, 0],
[1, 1],
[1, 2],
[2, 0],
[2, 1],
[2, 2]])
For the first approach if you don't want to use reshape another way is concatenation along the first axis using np.concatenate().
np.concatenate(np.indices(a.shape).T)
Related
I have a very long list named CB with possibly repeated elements. For example, CB could be [[0, 0], [0, 1], [0, 2], [0, 1], [1, 1], [1, 2], [0, 2], [1, 2], [2, 2]]. Each element in CB is a list of sorted numbers.
In this example, I want to keep
[[0,0], [0,1], [0,2], [1,1], [1,2], [2,2]].
I've tried to use CB1=np.unique(CB), but it returns [0,1,2], which is not what I wanted.
I also tried to use CB1=list(set(CB)), but got the following error: TypeError: unhashable type: 'list'.
How to solve this problem? It would be great if you could solve it with the simplest possible code. A python function or one line of code would be awesome. Thanks!
If you use np.unique, you want to use the axis keyword argument:
data = [[0, 0], [0, 1], [0, 2], [0, 1], [1, 1], [1, 2], [0, 2], [1, 2], [2, 2]]
np.unique(data, axis=0)
array([[0, 0],
[0, 1],
[0, 2],
[1, 1],
[1, 2],
[2, 2]])
if you want to use set, you need to convert to hashable type, e.g. tuple:
data = map(tuple, data)
set(data)
{(0, 0), (0, 1), (0, 2), (1, 1), (1, 2), (2, 2)}
if you need then converted back to the original list type, then the complete 1-liner would be:
data = list(map(list,set(map(tuple, data))))
I would like the order of b to equal the result of a below.
The result of b is not as I expected. I thought it would be sorting by the columns in ascending order but I think I misunderstood how lexsort works.
My goal is to be able to sort an array the way the df below is sorted.
I'm using lexsort because I think it would be the best thing to use for an array that also contained categorical values.
import numpy as np
import pandas as pd
x = np.array([[1,2],[1,3],[1,4],[2,1],[2,2],[2,3],[2,4],[0,1],[1,0],[0,2]])
a=pd.DataFrame(x).sort_values(by=[0,1], ascending=[0,1])
b=x[np.lexsort((x[:,1],x[:,0][::-1]))]
print(a)
print(b)
From the docs, it should be last, first to get the sort order:
sorter = np.lexsort((x[:, 1], x[:, 0]))
x[sorter][::-1] # sorting in descending order
Out[899]:
array([[2, 4],
[2, 3],
[2, 2],
[2, 1],
[1, 4],
[1, 3],
[1, 2],
[1, 0],
[0, 2],
[0, 1]])
To simulate descending on one end, with ascending on the other, you could combine np.unique, with np.split and np.concatenate:
temp = x[sorter]
_, s = np.unique(temp[:, 0], return_counts=True)
np.concatenate(np.split(temp, s.cumsum())[::-1])
Out[972]:
array([[2, 1],
[2, 2],
[2, 3],
[2, 4],
[1, 0],
[1, 2],
[1, 3],
[1, 4],
[0, 1],
[0, 2]])
I have a 2D Numpy array containing values from 0 to n.
I want to get a list of length n, such that the i'th element of that list is an array of all the indices with value i+1 (0 is excluded).
For example, for the input
array([[1, 0, 1],
[2, 2, 0]])
I'm expecting to get
[array([[0, 0], [0, 2]]), array([[1,0], [1,1]])]
I found this related question:
Get a list of all indices of repeated elements in a numpy array
which may be helpful, but I hoped to find a more direct solution that doesn't require flattening and sorting the array and that is as efficient as possible.
Here's a vectorized approach, which works for arrays of an arbitrary amount of dimensions. The idea of this solution is to extend the functionality of the return_index method in np.unique, and return an array of arrays, each containing the N-dimensional indices of unique values in a numpy array.
For a more compact solution, I've defined the following function along with some explanations throughout the different steps:
def ndix_unique(x):
"""
Returns an N-dimensional array of indices
of the unique values in x
----------
x: np.array
Array with arbitrary dimensions
Returns
-------
- 1D-array of sorted unique values
- Array of arrays. Each array contains the indices where a
given value in x is found
"""
x_flat = x.ravel()
ix_flat = np.argsort(x_flat)
u, ix_u = np.unique(x_flat[ix_flat], return_index=True)
ix_ndim = np.unravel_index(ix_flat, x.shape)
ix_ndim = np.c_[ix_ndim] if x.ndim > 1 else ix_flat
return u, np.split(ix_ndim, ix_u[1:])
Checking with the array from the question -
a = np.array([[1, 0, 1],[2, 2, 0]])
vals, ixs = ndix_unique(a)
print(vals)
array([0, 1, 2])
print(ixs)
[array([[0, 1],
[1, 2]]),
array([[0, 0],
[0, 2]]),
array([[1, 0],
[1, 1]])]
Lets try with this other case:
a = np.array([[1,1,4],[2,2,1],[3,3,1]])
vals, ixs = ndix_unique(a)
print(vals)
array([1, 2, 3, 4])
print(ixs)
array([array([[0, 0],
[0, 1],
[1, 2],
[2, 2]]),
array([[1, 0],
[1, 1]]),
array([[2, 0],
[2, 1]]),
array([[0, 2]])], dtype=object)
For a 1D array:
a = np.array([1,5,4,3,3])
vals, ixs = ndix_unique(a)
print(vals)
array([1, 3, 4, 5])
print(ixs)
array([array([0]), array([3, 4]), array([2]), array([1])], dtype=object)
Finally another example with a 3D ndarray:
a = np.array([[[1,1,2]],[[2,3,4]]])
vals, ixs = ndix_unique(a)
print(vals)
array([1, 2, 3, 4])
print(ixs)
array([array([[0, 0, 0],
[0, 0, 1]]),
array([[0, 0, 2],
[1, 0, 0]]),
array([[1, 0, 1]]),
array([[1, 0, 2]])], dtype=object)
You can first get non-zero elements in your array and then use argwhere in a list comprehension to get separate array for each non-zero element. Here np.unique(arr[arr!=0]) will give you the nonzero elements over which you can iterate to get the indices.
arr = np.array([[1, 0, 1],
[2, 2, 0]])
indices = [np.argwhere(arr==i) for i in np.unique(arr[arr!=0])]
# [array([[0, 0],
# [0, 2]]), array([[1, 0],
# [1, 1]])]
Let's say I have a 3d Numpy array:
array([[[0, 1, 2],
[0, 1, 2],
[0, 2, 5]]])
Is it possible to remove the first entry from all the rows (those inner most rows). In this case the 0 would be deleted in each row.
Giving us the following output:
[[[1, 2],
[1, 2],
[2, 5]]]
x
array([[[0, 1, 2],
[0, 1, 2],
[0, 2, 5]]])
x.shape
# (1, 3, 3)
You can use Ellipsis (...) to select across all the outermost axes, and slice out the first value from each row with 1:.
x[..., 1:]
array([[[1, 2],
[1, 2],
[2, 5]]])
x[..., 1:].shape
# (1, 3, 2)
To complement #coldspeed's response), slicing in numpy is very powerful and can be done in a variety of ways including with the colon operator : in the index, that is
print(x[:,:,1:])
# array([[[1, 2],
# [1, 2],
# [2, 5]]])
is equivalent to the established use of the ellipsis.
I have a 2D Numpy array containing values from 0 to n.
I want to get a list of length n, such that the i'th element of that list is an array of all the indices with value i+1 (0 is excluded).
For example, for the input
array([[1, 0, 1],
[2, 2, 0]])
I'm expecting to get
[array([[0, 0], [0, 2]]), array([[1,0], [1,1]])]
I found this related question:
Get a list of all indices of repeated elements in a numpy array
which may be helpful, but I hoped to find a more direct solution that doesn't require flattening and sorting the array and that is as efficient as possible.
Here's a vectorized approach, which works for arrays of an arbitrary amount of dimensions. The idea of this solution is to extend the functionality of the return_index method in np.unique, and return an array of arrays, each containing the N-dimensional indices of unique values in a numpy array.
For a more compact solution, I've defined the following function along with some explanations throughout the different steps:
def ndix_unique(x):
"""
Returns an N-dimensional array of indices
of the unique values in x
----------
x: np.array
Array with arbitrary dimensions
Returns
-------
- 1D-array of sorted unique values
- Array of arrays. Each array contains the indices where a
given value in x is found
"""
x_flat = x.ravel()
ix_flat = np.argsort(x_flat)
u, ix_u = np.unique(x_flat[ix_flat], return_index=True)
ix_ndim = np.unravel_index(ix_flat, x.shape)
ix_ndim = np.c_[ix_ndim] if x.ndim > 1 else ix_flat
return u, np.split(ix_ndim, ix_u[1:])
Checking with the array from the question -
a = np.array([[1, 0, 1],[2, 2, 0]])
vals, ixs = ndix_unique(a)
print(vals)
array([0, 1, 2])
print(ixs)
[array([[0, 1],
[1, 2]]),
array([[0, 0],
[0, 2]]),
array([[1, 0],
[1, 1]])]
Lets try with this other case:
a = np.array([[1,1,4],[2,2,1],[3,3,1]])
vals, ixs = ndix_unique(a)
print(vals)
array([1, 2, 3, 4])
print(ixs)
array([array([[0, 0],
[0, 1],
[1, 2],
[2, 2]]),
array([[1, 0],
[1, 1]]),
array([[2, 0],
[2, 1]]),
array([[0, 2]])], dtype=object)
For a 1D array:
a = np.array([1,5,4,3,3])
vals, ixs = ndix_unique(a)
print(vals)
array([1, 3, 4, 5])
print(ixs)
array([array([0]), array([3, 4]), array([2]), array([1])], dtype=object)
Finally another example with a 3D ndarray:
a = np.array([[[1,1,2]],[[2,3,4]]])
vals, ixs = ndix_unique(a)
print(vals)
array([1, 2, 3, 4])
print(ixs)
array([array([[0, 0, 0],
[0, 0, 1]]),
array([[0, 0, 2],
[1, 0, 0]]),
array([[1, 0, 1]]),
array([[1, 0, 2]])], dtype=object)
You can first get non-zero elements in your array and then use argwhere in a list comprehension to get separate array for each non-zero element. Here np.unique(arr[arr!=0]) will give you the nonzero elements over which you can iterate to get the indices.
arr = np.array([[1, 0, 1],
[2, 2, 0]])
indices = [np.argwhere(arr==i) for i in np.unique(arr[arr!=0])]
# [array([[0, 0],
# [0, 2]]), array([[1, 0],
# [1, 1]])]