Сортировка / кластеризация 2D-массива numpy в упорядоченной последовательности на основе нескольких столбцов

#python #arrays #numpy #sorting #sequence

Вопрос:

У меня есть массив 2D numpy, подобный этому:

  [[4 5 2] 
  [5 5 1]
  [5 4 5]
  [5 3 4]
  [5 4 4]
  [4 3 2]]
 

Я хотел бы отсортировать / кластеризировать этот массив, найдя последовательность в массиве следующим row[0]>=row[1]>=row[2] образом , row[0]>=row[2]>row[1] … таким образом, строка массива находится в упорядоченной последовательности.

Я пытался использовать код: lexdf = df[np.lexsort((df[:,2], df[:,1],df[:,0]))][::-1] , однако я этого не хочу. Вывод lexsort:

  [[5 5 1]
  [5 4 5]
  [5 4 4]
  [5 3 4]
  [4 5 2] 
  [4 3 2]]
 

Результат, который я хотел бы иметь:

  [[5 5 1]
  [5 4 4]
  [4 3 2]
  [5 4 5]
  [5 3 4]
  [4 5 2]] 
 

или разбейте его на три части:

  [[5 5 1]
 [5 4 4]
 [4 3 2]]

 [[5 4 5]
 [5 3 4]]

 [[4 5 2]]
 

И я хотел бы применить это к массиву с большим количеством столбцов, поэтому было бы лучше сделать это без итерации. Есть идеи для создания такого вывода?

Комментарии:

1. Ваша нотация нестандартна, что затрудняет отслеживание вашего описания

2. Что это row[0]>=row[1]>=row[2] такое?

3. @MadPhysicist Я хотел бы отсортировать строки в 2D-массиве на основе столбца. Это row[0]>=row[1]>row[2] означает, что нужно найти строки в этом массиве, чтобы значение в первом столбце было больше или равно значению во втором столбце, а значение во втором столбце больше, чем значение в третьем столбце.

4. Я до сих пор не понимаю, как вы переходите от этого к желаемому результату. Возможно, вы могли бы написать функцию сравнения, которую вы могли бы использовать для сортировки, или ключ сортировки? В принципе, однозначно покажите, как вы бы решили, какая строка идет первой.

5. Звучит как проблема с графом: учитывая ориентированный граф, разделите граф на простые деревья (без каких-либо ветвей).

Ответ №1:

Я не знаю, как это сделать в numpy, за исключением, может быть, некоторых странных хаков функций numpy.split .

Вот способ получить ваши группы с помощью списков python:

 from itertools import groupby, pairwise

def f(sublist):
    return [x <= y for x,y in pairwise(sublist)]

# NOTE: itertools.pairwise requires python>=3.10
# For python<=3.9, use one of those alternatives:
# * more_itertools.pairwise(sublist)
# * zip(sublist, sublist[1:])

a = [[4, 5, 2], 
  [5, 5, 1],
  [5, 4, 5],
  [5, 3, 4],
  [5, 4, 4],
  [4, 3, 2]]

b = [list(g) for _,g in groupby(sorted(a, key=f), key=f)]

print(b)
# [[[4, 3, 2]],
#  [[5, 4, 5], [5, 3, 4], [5, 4, 4]],
#  [[4, 5, 2], [5, 5, 1]]]
 

Примечание: комбинация groupby sorted на самом деле немного неэффективна, поскольку sorted занимает n логарифмическое (n) время. Линейной альтернативой является группирование с использованием словаря списков. См., Например, Функцию itertoolz.groupby из модуля toolz .

Комментарии:

1. Спасибо! Это действительно то, что мне нужно. Просто небольшая вещь, если я хочу получить желаемый результат, этого x < y не должно быть x <= y . Я хотел бы спросить еще одну вещь, если это возможно: если я хотел бы сравнить только значения первых нескольких столбцов, а не весь столбец, что мне делать? Например, я хочу сравнить только первые два столбца.

2. Я уже нашел способ! Спасибо за ваше понимание!