У меня есть массив чисел, и я хотел бы создать еще один массив, представляющий ранг каждого элемента в первом массиве. Я использую Python и NumPy.
Например:
array = [4,2,7,1]
ranks = [2,1,3,0]
Вот лучший метод, который я придумал:
array = numpy.array([4,2,7,1])
temp = array.argsort()
ranks = numpy.arange(len(array))[temp.argsort()]
Есть ли более эффективные / более быстрые методы, позволяющие избежать двойной сортировки массива?
ranks = temp.argsort()
.Ответы:
Используйте нарезку слева на последнем шаге:
Это позволяет избежать двойной сортировки, инвертируя перестановку на последнем шаге.
источник
Используйте argsort дважды, сначала для получения порядка массива, а затем для получения ранжирования:
При работе с двумерными (или более крупными) массивами не забудьте передать аргумент оси в argsort, чтобы упорядочить по правильной оси.
источник
[4,2,7,1,1]
), выходные данные будут ранжировать эти числа на основе их позиции в массиве ([3,2,4,0,1]
)argsort
.array = np.random.rand(10)
должна бытьarray = np.random.rand(n)
.Этому вопросу несколько лет, и принятый ответ отличный, но я думаю, что следующее все же стоит упомянуть. Если вы не против зависимости от
scipy
, вы можете использоватьscipy.stats.rankdata
:Приятной особенностью
rankdata
является то, чтоmethod
аргумент предоставляет несколько вариантов обработки связей. Например, есть три вхождения 20 и два вхождения 40 вb
:По умолчанию связанным значениям присваивается средний рейтинг:
method='ordinal'
присваивает последовательные ранги:method='min'
присваивает минимальный ранг связанных значений всем связанным значениям:Дополнительные параметры см. В строке документации.
источник
rankdata
похоже, используется тот же механизм, что и в принятом ответе, для внутренней генерации начального рейтинга.Я попытался расширить оба решения для массивов A более чем одного измерения, предполагая, что вы обрабатываете свой массив построчно (ось = 1).
Я расширил первый код циклом по строкам; возможно это можно улучшить
А второй, следуя предложению k.rooijers, становится:
Я произвольно сгенерировал 400 массивов с формой (1000,100); первый код занял около 7,5, второй 3,8.
источник
Векторизованную версию усредненного ранга см. Ниже. Мне нравится np.unique, он действительно расширяет рамки того, какой код можно и нельзя эффективно векторизовать. Помимо отказа от циклов for в Python, этот подход также позволяет избежать неявного двойного цикла над 'a'.
источник
Помимо элегантности и краткости решений, существует еще вопрос производительности. Вот небольшой тест:
источник
rankdata(l, method='ordinal') - 1
.Дважды используйте argsort (), чтобы сделать это:
источник
Я пробовал описанные выше методы, но не смог, потому что у меня было много zeores. Да, даже с поплавками могут быть важны повторяющиеся элементы.
Итак, я написал модифицированное одномерное решение, добавив этап проверки связи:
Я считаю, что это настолько эффективно, насколько это возможно.
источник
Мне понравился метод k.rooijers, но, как писал rcoup, повторяющиеся числа ранжируются в соответствии с позицией массива. Для меня это было бесполезно, поэтому я изменил версию, чтобы постобработать ранги и объединить любые повторяющиеся числа в комбинированный средний ранг:
Я надеюсь, что это может помочь и другим, я пытался найти другое решение, но не нашел ...
источник
argsort и slice - это операции симметрии.
попробуйте дважды срезать вместо двух аргументов. поскольку срез быстрее, чем argsort
источник
Более общий вариант одного из ответов:
См. Раздел Как использовать numpy.argsort () в качестве индексов более чем в двух измерениях? обобщить на более тусклые.
источник