Сортировка массивов в NumPy по столбцам - PullRequest
271 голосов
/ 13 мая 2010

Как мне отсортировать массив в NumPy по n-му столбцу?

Например,

a = array([[9, 2, 3],
           [4, 5, 6],
           [7, 0, 5]])

Я бы хотел отсортировать строки по второму столбцу, чтобы получить ответ:

array([[7, 0, 5],
       [9, 2, 3],
       [4, 5, 6]])

Ответы [ 9 ]

600 голосов
/ 13 мая 2010

Полагаю, это работает: a[a[:,1].argsort()]

Указывает на второй столбец a и сортирует его по нему соответственно.

116 голосов
/ 13 мая 2010

@ steve на самом деле самый элегантный способ сделать это.

Для «правильного» способа см. Аргумент ключевого слова заказа numpy.ndarray.sort

Однако вам нужно будет просмотреть свой массив как массив с полями (структурированный массив).

"Правильный" способ довольно уродлив, если вы изначально не определяли свой массив с полями ...

В качестве быстрого примера, чтобы отсортировать его и вернуть копию:

In [1]: import numpy as np

In [2]: a = np.array([[1,2,3],[4,5,6],[0,0,1]])

In [3]: np.sort(a.view('i8,i8,i8'), order=['f1'], axis=0).view(np.int)
Out[3]: 
array([[0, 0, 1],
       [1, 2, 3],
       [4, 5, 6]])

Чтобы отсортировать на месте:

In [6]: a.view('i8,i8,i8').sort(order=['f1'], axis=0) #<-- returns None

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

@ Стив действительно самый элегантный способ сделать это, насколько я знаю ...

Единственное преимущество этого метода в том, что аргумент "order" - это список полей, по которым упорядочен поиск. Например, вы можете отсортировать по второму столбцу, затем по третьему столбцу, затем по первому столбцу, указав order = ['f1', 'f2', 'f0'].

23 голосов
/ 05 июля 2016

Вы можете сортировать по нескольким столбцам в соответствии с методом Стива Тджоа, используя стабильную сортировку, такую ​​как сортировка слиянием, и сортируя индексы от наименее значимых к наиболее значимым столбцам:

a = a[a[:,2].argsort()] # First sort doesn't need to be stable.
a = a[a[:,1].argsort(kind='mergesort')]
a = a[a[:,0].argsort(kind='mergesort')]

Это сортирует по столбцу 0, затем 1, затем 2.

19 голосов
/ 29 сентября 2011

С вики документации Python , я думаю, вы можете сделать:

a = ([[1, 2, 3], [4, 5, 6], [0, 0, 1]]); 
a = sorted(a, key=lambda a_entry: a_entry[1]) 
print a

Вывод:

[[[0, 0, 1], [1, 2, 3], [4, 5, 6]]]
16 голосов
/ 25 февраля 2016

В случае, если кто-то хочет использовать сортировку в критической части своих программ, вот сравнение производительности для различных предложений:

import numpy as np
table = np.random.rand(5000, 10)

%timeit table.view('f8,f8,f8,f8,f8,f8,f8,f8,f8,f8').sort(order=['f9'], axis=0)
1000 loops, best of 3: 1.88 ms per loop

%timeit table[table[:,9].argsort()]
10000 loops, best of 3: 180 µs per loop

import pandas as pd
df = pd.DataFrame(table)
%timeit df.sort_values(9, ascending=True)
1000 loops, best of 3: 400 µs per loop

Итак, похоже, индексирование с помощью argsort является самым быстрым на данный момент методом ...

14 голосов
/ 03 июня 2015

Из списка рассылки NumPy , вот еще одно решение:

>>> a
array([[1, 2],
       [0, 0],
       [1, 0],
       [0, 2],
       [2, 1],
       [1, 0],
       [1, 0],
       [0, 0],
       [1, 0],
      [2, 2]])
>>> a[np.lexsort(np.fliplr(a).T)]
array([[0, 0],
       [0, 0],
       [0, 2],
       [1, 0],
       [1, 0],
       [1, 0],
       [1, 0],
       [1, 2],
       [2, 1],
       [2, 2]])
4 голосов
/ 04 ноября 2016

У меня была похожая проблема.

Моя проблема:

Я хочу вычислить SVD, и мне нужно отсортировать мои собственные значения в порядке убывания. Но я хочу сохранить соответствие между собственными значениями и собственными векторами. Мои собственные значения были в первом ряду, а соответствующий собственный вектор под ним в том же столбце.

Итак, я хочу отсортировать двумерный массив по столбцам по первой строке в порядке убывания.

Мое решение

a = a[::, a[0,].argsort()[::-1]]

Так как это работает?

a[0,] - это только первая строка, по которой я хочу отсортировать.

Теперь я использую argsort для получения порядка индексов.

Я использую [::-1], потому что мне нужен нисходящий порядок.

Наконец, я использую a[::, ...], чтобы получить представление со столбцами в правильном порядке.

1 голос
/ 07 августа 2016

Немного более сложный lexsort пример - спуск по 1-му столбцу, второй по возрастанию по 2-му. Трюки с lexsort заключаются в том, что он сортирует по строкам (отсюда .T) и отдает приоритет последним.

In [120]: b=np.array([[1,2,1],[3,1,2],[1,1,3],[2,3,4],[3,2,5],[2,1,6]])
In [121]: b
Out[121]: 
array([[1, 2, 1],
       [3, 1, 2],
       [1, 1, 3],
       [2, 3, 4],
       [3, 2, 5],
       [2, 1, 6]])
In [122]: b[np.lexsort(([1,-1]*b[:,[1,0]]).T)]
Out[122]: 
array([[3, 1, 2],
       [3, 2, 5],
       [2, 1, 6],
       [2, 3, 4],
       [1, 1, 3],
       [1, 2, 1]])
0 голосов
/ 30 января 2018

Вот еще одно решение, учитывающее все столбцы (более компактный способ ответа J.J );

ar=np.array([[0, 0, 0, 1],
             [1, 0, 1, 0],
             [0, 1, 0, 0],
             [1, 0, 0, 1],
             [0, 0, 1, 0],
             [1, 1, 0, 0]])

Сортировка с помощью lexsort,

ar[np.lexsort(([ar[:, i] for i in range(ar.shape[1]-1, -1, -1)]))]

Выход:

array([[0, 0, 0, 1],
       [0, 0, 1, 0],
       [0, 1, 0, 0],
       [1, 0, 0, 1],
       [1, 0, 1, 0],
       [1, 1, 0, 0]])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...