Sort a multidimensional NumPy array by a norm by dimension

I work with a multidimensional array NumPy a, which is the "vector", for example 2x2. I want to sort aso that matrices are 2x2sorted by their row norms.

import numpy as np
a = np.array([[[3, 4],
               [1, 2]],

              [[5, 6],
               [7, 8]]])    
sortidxs = np.argsort(np.linalg.norm(a, axis=-1))
a = np.array([a[_][sortidxs[_]] for _ in range(a.shape[0])])

# And the final output should be:

print(a)
[[[1 2]
  [3 4]]

  [[5 6]
  [7 8]]]

The above code snippet does what I'm looking for (not really, look at the Edit below). But I was looking for a way to avoid the loop

a = np.array([a[_][sortidxs[_]] for _ in range(a.shape[0])])

- Change -

In the example above, the important part of the question is missing. amay have more empty dimensions ie

a = np.array([[[3, 4],
               [1, 2]],

              [[5, 6],
               [7, 8]]])
a = a.reshape((2,1,2,2))

a now looks like this:

In [257]: a
Out[257]: 
array([[[[3, 4],
         [1, 2]]],

       [[[5, 6],
         [7, 8]]]])

and after sorting it should be

In [259]: a
Out[259]: 
array([[[[1, 2],
         [3, 4]]],

       [[[5, 6],
         [7, 8]]]])

amay also have the following size (1,2,2,2)or more of such “empty” dimensions at the beginning. I would like this view to work in these cases.

+4
2

advanced-indexing -

a[np.arange(a.shape[0])[:,None], sortidxs]

-

In [144]: a = np.random.randint(0,9,(2,3,4))

In [145]: a
Out[145]: 
array([[[1, 1, 5, 5],
        [1, 1, 7, 5],
        [6, 1, 2, 8]],

       [[7, 2, 5, 4],
        [3, 7, 3, 7],
        [8, 4, 4, 6]]])

In [146]: sortidxs = np.argsort(np.linalg.norm(a, axis=-1))

In [147]: np.array([a[_][sortidxs[_]] for _ in range(a.shape[0])])
Out[147]: 
array([[[1, 1, 5, 5],
        [1, 1, 7, 5],
        [6, 1, 2, 8]],

       [[7, 2, 5, 4],
        [3, 7, 3, 7],
        [8, 4, 4, 6]]])

In [149]: a[np.arange(a.shape[0])[:,None], sortidxs]
Out[149]: 
array([[[1, 1, 5, 5],
        [1, 1, 7, 5],
        [6, 1, 2, 8]],

       [[7, 2, 5, 4],
        [3, 7, 3, 7],
        [8, 4, 4, 6]]])

sortidxs np.einsum -

sortidxs = np.einsum('ijk,ijk->ij',a,a).argsort()

-

In [94]: a = np.random.randint(0,9,(20,30,40))

In [95]: %timeit np.argsort(np.linalg.norm(a, axis=-1))
10000 loops, best of 3: 63.5 µs per loop

In [96]: %timeit np.einsum('ijk,ijk->ij',a,a).argsort()
10000 loops, best of 3: 19.7 µs per loop

In [97]: a = np.random.randint(0,9,(200,300,400))

In [98]: %timeit np.argsort(np.linalg.norm(a, axis=-1))
10 loops, best of 3: 88.6 ms per loop

In [99]: %timeit np.einsum('ijk,ijk->ij',a,a).argsort()
10 loops, best of 3: 22.6 ms per loop

a, 4D, .

1] : np.arange(a.shape[0]) .

2] : np.arange(a.shape[0]) .

3] : sortidxs .

, :

m,n,r,s = a.shape
out = a[np.arange(m)[:,None,None],np.arange(n)[:,None], sortidxs]

dim (dim = 1)

, , 0 , , , :

a[np.arange(m)[:,None,None],0, sortidxs]

-

In [58]: a = np.array([[[3, 4],
    ...:                [1, 2]],
    ...: 
    ...:               [[5, 6],
    ...:                [7, 8]]])
    ...: 
    ...: a = a.reshape((2,1,2,2))
    ...: 

In [59]: sortidxs = np.argsort(np.linalg.norm(a, axis=-1))

In [60]: a[np.arange(a.shape[0])[:,None,None],0, sortidxs]
Out[60]: 
array([[[[1, 2],
         [3, 4]]],


       [[[5, 6],
         [7, 8]]]])

(2,3,4), -

In [70]: a = np.random.randint(0,9,(2,1,3,4))

In [71]: a
Out[71]: 
array([[[[6, 4, 8, 6],
         [4, 0, 1, 0],
         [5, 3, 2, 5]]],


       [[[3, 6, 0, 4],
         [6, 2, 5, 2],
         [0, 8, 0, 8]]]])

In [72]: sortidxs = np.argsort(np.linalg.norm(a, axis=-1))

In [73]: sortidxs
Out[73]: 
array([[[1, 2, 0]],

       [[0, 1, 2]]])

In [74]: a[np.arange(a.shape[0])[:,None,None],0, sortidxs]
Out[74]: 
array([[[[4, 0, 1, 0],
         [5, 3, 2, 5],
         [6, 4, 8, 6]]],


       [[[3, 6, 0, 4],
         [6, 2, 5, 2],
         [0, 8, 0, 8]]]])
+3

sortidxs ( ), ragne np.arange(a.shape[0]) :

In [31]: x,y, z = a.shape
In [32]: i, j = sortidxs.shape
In [33]: a[np.repeat(np.arange(x)[:, none], i, 1),sortidxs]

Out[33]: 
array([[[1, 2],
        [3, 4]],

       [[5, 6],
        [7, 8]]])

( ) np.arange(x)[:, None] repeat(), , 2- 3- .. repeat . , .

In [107]: a[np.arange(x)[:, None],sortidxs]
Out[107]: 
array([[[1, 2],
        [3, 4]],

       [[5, 6],
        [7, 8]]])
+1

Source: https://habr.com/ru/post/1674317/


All Articles