masking array with logical values along an arbitrary axis - python

Suppose I have a multidimensional array and a vector of logical values. I want to select items along an arbitrary (n-th) dimension. In the following example I am going to select the first and third values along the second dimension:
>>> A = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])
>>> mask = np.array([True, False, True, False])
>>> dim_to_mask = 1 # i.e. 2nd dimension because it's 0-indexed
>>> B = ... # here do mask the dim_to_mask-th dimension - HOW???
>>> B
[[1, 3],
[5, 7],
[9, 11]]
Note: assume that the length of the logical vector corresponds to the length of the given axis.
I know it would be easy if the array is just one-dimensional using [] operator, but this is multidimensional problem.
Actually I want something like function take(indices, axis) which selects given indices along an arbitrary axis. The only difference is that I do have logical values instead of numeric indices.
I am also aiming at the fastest solution so converting vector of logical values to indices and using take is probably not the best solution.
I guess it must be something obvious which I am missing. :)

You could use np.compress:
>>> A.compress(mask, axis=1)
array([[ 1, 3],
[ 5, 7],
[ 9, 11]])
This function returns slices of an array along a particular axis. It accepts a boolean array with which to make the selections.

Related

get value from tensor by using index array python

I have an array A :
A = [[1, 2 ,3 ,4],
[5, 6 ,7 ,8],
[9, 10 ,11 ,12],]
and I want to get the 2nd row in the 3rd element (i.e. '7') :
I can do it by:
A[1,2]
For the general dimension number I want to have something generic.
Given index list B=[1,2]
I want to have something like MATLAB indexing:
A[B] or A[*B]
The first gives 2 rows and the second results in an error.
How can I do this?
edit: type(A)=type(B)=np.array
You don't need to unpack collection with "*" because numpy supports tuple indexing. You problem is that there is difference between indexing by list and by tuple. So,
import numpy as np
A = np.array([
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12]
])
print("indexing by list:\n", A[[0, 1]], '\n')
# Output:
# indexing by list:
# [[1 2 3 4]
# [5 6 7 8]]
print("indexing by tuple:\n", A[(0, 1)])
# Output:
# indexing by tuple:
# 2
Hope, it helps. For the further reading about numpy indexing.
As an alternative, suppose you are interested in "array indexing", i.e., getting an array of values back of length L, where each value in the array is from a location in A. You would like to indicate these locations via an index of some kind.
Suppose A is N-dimensional. Array indexing solves this problem by letting you pass a tuple of N lists of length L. The ith list gives the indices corresponding to the ith dimension in A. In the simplest case, the index lists can be length-one (L=1):
>>> A[[1], [2]]
array([7])
But the index lists could be longer (L=5):
>>> A[[1,1,1,1,0], [2,2,2,2,0]]
array([7, 7, 7, 7, 1])
I emphasize that this is a tuple of lists; you can also go:
>>> first_axis, second_axis = [1,1,1,1,0], [2,2,2,2,0]
>>> A[(first_axis,second_axis)]
array([7, 7, 7, 7, 1])
You can also pass a non-tuple sequence (a list of lists rather than a tuple of lists) A[[first_axis,second_axis]] but in NumPy version 1.21.2, a FutureWarning is given noting that this is deprecated.
Another example here: https://stackoverflow.com/a/23435869/4901005

How to properly concatenate two 1D arrays without flattening?

How do I concatenate properly two numpy vectors without flattening the result? This is really obvious with append, but it gets shamefully messy when turning to numpy.
I've tried concatenate (expliciting axis and not), hstack, vstack. All with no results.
In [1]: a
Out[1]: array([1, 2, 3])
In [2]: b
Out[2]: array([6, 7, 8])
In [3]: c = np.concatenate((a,b),axis=0)
In [4]: c
Out[4]: array([1, 2, 3, 6, 7, 8])
Note that the code above works indeed if a and b are lists instead of numpy arrays.
The output I want:
Out[4]: array([[1, 2, 3], [6, 7, 8]])
EDIT
vstack works indeed for a and b as in above. It does not in my real life case, where I want to iteratively fill an empty array with vectors of some dimension.
hist=[]
for i in range(len(filenames)):
fileload = np.load(filenames[i])
maxarray.append(fileload['maxamp'])
hist_t, bins_t = np.histogram(maxarray[i], bins=np.arange(0,4097,4))
hist = np.vstack((hist,hist_t))
SOLUTION:
I found the solution: you have to properly initialize the array e.g.: How to add a new row to an empty numpy array
For np.concatenate to work here the input arrays should have two dimensions, as you wasnt a concatenation along the second axis here, and the input arrays only have 1 dimension.
You can use np.vstack here, which as explained in the docs:
It is equivalent to concatenation along the first axis after 1-D arrays of shape (N,) have been reshaped to (1,N)
a = np.array([1, 2, 3])
b = np.array([6, 7, 8])
np.vstack([a, b])
array([[1, 2, 3],
[6, 7, 8]])

Numpy repeating a row or column

Suppose we have the matrix A:
A = [1,2,3
4,5,6
7,8,9]
I want to know if there is a way to obtain:
B = [1,2,3
4,5,6
7,8,9
7,8,9]
As well as:
B = [1,2,3,3
4,5,6,6
7,8,9,9]
This is because the function I want to implement is the following:
U(i,j) = min(A(i+1,j)^2, A(i,j)^2)
V(i,j) = min(A(i,j+1)^2, A(i,j)^2)
And the numpy.minimum seems to need two arrays with equal shapes.
My idea is the following:
np.minimum(np.square(A[1:]), np.square(A[:]))
but it will fail.
For your particular example you could use numpy.hstack and numpy.vstack:
In [11]: np.vstack((A, A[-1]))
Out[11]:
array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
[7, 8, 9]])
In [12]: np.hstack((A, A[:, [-1]]))
Out[12]:
array([[1, 2, 3, 3],
[4, 5, 6, 6],
[7, 8, 9, 9]])
An alternative to the last one is np.hstack((A, np.atleast_2d(A[:,-1]).T)) or np.vstack((A.T, A.T[-1])).T): you can't hstack a (3,) array to a (3,3) one without putting the elements in the rows of a (3,1) array.
A good answer to your literal question is provided by #xnx, but I wonder whether what you actually need is something else.
This type of question comes up a lot in comparisons, and the usual solution is to take only the valid entries, rather than using a misaligned comparison. That is, something like this is common:
import numpy as np
A = np.arange(9).reshape((3,3))
U = np.minimum(A[1:,:]**2, A[:-1,:]**2)
V = np.minimum(A[:,1:]**2, A[:,:-1]**2)
print U
# [[ 0 1 4]
# [ 9 16 25]]
print V
# [[ 0 1]
# [ 9 16]
# [36 49]]
I suspect that you're probably thinking, "that's a hassle, now U and V have different shapes than A, which is not what I want". But, to this I'd say, "yes, it is a hassle, but it's better to deal with the problem up front and directly than hide it within an invalid row of an array."
A standard example and typical use case of this approach would be numpy.diff, where, "the shape of the output is the same as a except along axis where the dimension is smaller by n."

Reshaping an array to 2-D by specifying only the column size

I have a vector of length, lets say 10:
foo = np.arange(2,12)
In order to convert it to a 2-D array, with lets say 2 columns, I use the command reshape with following arguments:
foo.reshape(len(foo)/2, 2)
I was wondering if there is a more elegant way/syntax to do that (may be sth like foo.reshape(,2) )
You almost had it! You can use -1.
>>> foo.reshape(-1, 2)
array([[ 2, 3],
[ 4, 5],
[ 6, 7],
[ 8, 9],
[10, 11]])
As the reshape docs say:
newshape : int or tuple of ints
The new shape should be compatible with the original shape. If
an integer, then the result will be a 1-D array of that length.
One shape dimension can be -1. In this case, the value is inferred
from the length of the array and remaining dimensions.

Use index of maximum value on a defined axis

I want to extract the values of an array "B" at the same index of the maximum of each line of the matrix "A". to find the index I use the numpy function "numpy.argmax" like this:
>>> A=numpy.asarray([[0,1,6],[3,2,4]]);A
array([[0, 1, 6],
[3, 2, 4]])
>>> argA=numpy.argmax(A,axis=1);argA
array([2, 2])
The problem is that I don't know how to use "argA" to extract the values in the array "B"
Each entry in argA corresponds to the index position of a maximum value within a corresponding row. The rows are not explicit (due to using axis=1), but correspond to the index for each entry. So you need to add them in to get at the elements you are after.
>>> A[[0,1], argA]
array([6, 4])
So:
>>> B
array([[ 9, 8, 2],
[ 3, 4, 5]])
>>> B[[0,1], argA] = 84,89
>>> B
array([[ 9, 8, 84],
[ 3, 4, 89]])
to generalise use:
>>> B[np.arange(A.shape[0]),argA]
You can use an array directly as an index - this is actually as simple as:
B[:, arga]
eg:
>>> A[:,argA]
array([[6, 6],
[4, 4]])
This may appear a little inefficient, but you could use:
A.take(argA, axis=1).diagonal()
Instead of A.take you can use A[:, argA] but take is more explicit about the axis.
You could use ravel_multi_index to convert to flat indices:
A.take(np.ravel_multi_index((np.arange(len(argA)), argA), A.shape))

Categories