Sorting a 2D numpy array by multiple axes

前端 未结 7 2020
小蘑菇
小蘑菇 2020-11-27 11:23

I have a 2D numpy array of shape (N,2) which is holding N points (x and y coordinates). For example:

array([[3, 2],
       [6, 2],
       [3, 6],
       [3,          


        
相关标签:
7条回答
  • 2020-11-27 11:48

    Using lexsort:

    import numpy as np    
    a = np.array([(3, 2), (6, 2), (3, 6), (3, 4), (5, 3)])
    
    ind = np.lexsort((a[:,1],a[:,0]))    
    
    a[ind]
    # array([[3, 2],
    #       [3, 4],
    #       [3, 6],
    #       [5, 3],
    #       [6, 2]])
    

    a.ravel() returns a view if a is C_CONTIGUOUS. If that is true, @ars's method, slightly modifed by using ravel instead of flatten, yields a nice way to sort a in-place:

    a = np.array([(3, 2), (6, 2), (3, 6), (3, 4), (5, 3)])
    dt = [('col1', a.dtype),('col2', a.dtype)]
    assert a.flags['C_CONTIGUOUS']
    b = a.ravel().view(dt)
    b.sort(order=['col1','col2'])
    

    Since b is a view of a, sorting b sorts a as well:

    print(a)
    # [[3 2]
    #  [3 4]
    #  [3 6]
    #  [5 3]
    #  [6 2]]
    
    0 讨论(0)
  • 2020-11-27 11:49

    You can use np.complex_sort. This has the side effect of changing your data to floating point, I hope that's not a problem:

    >>> a = np.array([[3, 2], [6, 2], [3, 6], [3, 4], [5, 3]])
    >>> atmp = np.sort_complex(a[:,0] + a[:,1]*1j)
    >>> b = np.array([[np.real(x), np.imag(x)] for x in atmp])
    >>> b
    array([[ 3.,  2.],
           [ 3.,  4.],
           [ 3.,  6.],
           [ 5.,  3.],
           [ 6.,  2.]])
    
    0 讨论(0)
  • 2020-11-27 11:52

    The title says "sorting 2D arrays". Although the questioner uses an (N,2)-shaped array, it's possible to generalize unutbu's solution to work with any (N,M) array, as that's what people might actually be looking for.

    One could transpose the array and use slice notation with negative step to pass all the columns to lexsort in reversed order:

    >>> import numpy as np
    >>> a = np.random.randint(1, 6, (10, 3))
    >>> a
    array([[4, 2, 3],
           [4, 2, 5],
           [3, 5, 5],
           [1, 5, 5],
           [3, 2, 1],
           [5, 2, 2],
           [3, 2, 3],
           [4, 3, 4],
           [3, 4, 1],
           [5, 3, 4]])
    
    >>> a[np.lexsort(np.transpose(a)[::-1])]
    array([[1, 5, 5],
           [3, 2, 1],
           [3, 2, 3],
           [3, 4, 1],
           [3, 5, 5],
           [4, 2, 3],
           [4, 2, 5],
           [4, 3, 4],
           [5, 2, 2],
           [5, 3, 4]])
    
    0 讨论(0)
  • 2020-11-27 11:52

    The numpy_indexed package (disclaimer: I am its author) can be used to solve these kind of processing-on-nd-array problems in an efficient fully vectorized manner:

    import numpy_indexed as npi
    npi.sort(a)  # by default along axis=0, but configurable
    
    0 讨论(0)
  • 2020-11-27 12:00

    I found one way to do it:

    from numpy import array
    a = array([(3,2),(6,2),(3,6),(3,4),(5,3)])
    array(sorted(sorted(a,key=lambda e:e[1]),key=lambda e:e[0]))
    

    It's pretty terrible to have to sort twice (and use the plain python sorted function instead of a faster numpy sort), but it does fit nicely on one line.

    0 讨论(0)
  • 2020-11-27 12:02

    EDIT: removed bad answer.

    Here's one way to do it using an intermediate structured array:

    from numpy import array
    
    a = array([[3, 2], [6, 2], [3, 6], [3, 4], [5, 3]])
    
    b = a.flatten()
    b.dtype = [('x', '<i4'), ('y', '<i4')]
    b.sort()
    b.dtype = '<i4'
    b.shape = a.shape
    
    print b
    

    which gives the desired output:

    [[3 2]
     [3 4]
     [3 6]
     [5 3]
     [6 2]]
    

    Not sure if this is quite the best way to go about it though.

    0 讨论(0)
提交回复
热议问题