Как быстро найти минимальный элемент справа для каждого элемента массива Numpy?

Допустим, у меня есть массив:

a = [1,4,3,6,4]

Я хочу получить массив, в котором для каждого элемента есть наименьшее значение в a справа (включительно). То есть для a я бы хотел создать массив:

[1,3,3,4,4]

Есть ли быстрый и лаконичный способ сделать это?

Какой должен быть результат для a = np.array([1,4,3,6,5,6,4])?

mozway 03.07.2024 15:46

@BigBen Да, извини, исправил опечатку

ufghd34 04.07.2024 05:39
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
2
161
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Ответ принят как подходящий

Ваш вопрос на самом деле неоднозначный. Хотите ли вы рассмотреть следующее значение или все следующие значения?

учитывая все следующие значения

вычислите накопленный минимум в перевернутом массиве с помощью минимум.аккумулировать:

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

out = np.minimum.accumulate(a[::-1])[::-1]

Выход:

array([1, 3, 3, 4, 4])

С чистым Python и itertools.accumulate:

from itertools import accumulate

a = [1,4,3,6,4]

out = list(accumulate(a[::-1], min))[::-1]
# [1, 3, 3, 4, 4]

учитывая только следующее значение

Вы можете изменить значения и использовать np.minimum:

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

out = np.minimum(a, np.r_[a[1:], a[-1]])

Выход:

array([1, 3, 3, 4, 4])

или сравните последовательные значения и создайте маску для изменения a на месте:

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

m = a[:-1] > a[1:]
# or
# m = np.diff(a) < 0

a[np.r_[m, False]] = a[1:][m]

Изменено a:

array([1, 3, 3, 4, 4])

разница

a = np.array([1,4,3,6,5,6,4])

np.minimum.accumulate(a[::-1])[::-1]
# array([1, 3, 3, 4, 4, 4, 4])

np.minimum(a, np.r_[a[1:], a[-1]])
# array([1, 3, 3, 5, 5, 4, 4])

Я думаю, вы имеете в виду, что вам нужен наименьший из элементов справа от списка (включительно). Именно так я интерпретирую ваш пример. Если да, то это решение:

b = [np.min(a[i:]) for i in range(len(a))]

Это довольно кратко. Если вы хотите, чтобы это был еще один массив np:

b = np.array([np.min(a[i:]) for i in range(len(a))])

Обновлено:

Это простой способ сделать это, но он не такой быстрый, как способ Mozway. Конкретно:

out = np.minimum.accumulate(a[::-1])[::-1]

что он и написал в своем ответе. Выполнение этих двух вычислений 100_000 раз занимает 2,2487 с для моего решения и 0,0972 с для решения Mozway, что делает его решение примерно в 23 раза быстрее. Я бы порекомендовал его решение.

Мое решение на самом деле медленнее, чем создание его на чистом Python без numpy. Вот решение на Python без numpy:

result = [min(b) for i in range(len(a))]

Это занимает 0,1890 с. Это все еще примерно в 2 раза медленнее, чем чистый способ, но ок. В 12 раз быстрее, чем смесь, которую я предоставил.

Решение с использованием pandas, предоставленное PaulS, очень интересное, но медленное со временем 7,7083 с.

Чтобы внести ясность, измеренное время относится к длинному списку/массиву из 6 элементов, и, как пишет Mozway, для более длинных списков, вероятно, разница еще больше.

Это был бы крайне неэффективный способ. Вам не нужно перезапускать все, чтобы вычислить текущий минимум. np.minimum.accumulate(a[::-1])[::-1] делает то же самое эффективно (в 2000 раз быстрее для 10 тысяч элементов, в 7000 раз быстрее для 100 тысяч, для большего количества это может даже не работать)

mozway 03.07.2024 16:32

Я надеюсь, что itertools.accumulate сможет дать вам желаемый результат

from itertools import accumulate
list(accumulate(a[::-1], lambda x, y: [x,y][y <= x]))[::-1]

# [1, 3, 3, 4, 4]

Я только что добавил вариант accumulate к своему ответу, но list(accumulate(a[::-1], min))[::-1] достаточно;)

mozway 03.07.2024 16:36

@mozway ага, только что увидел это в твоем ответе, удалю свое решение

ThomasIsCoding 03.07.2024 16:37

Вы можете оставить это!

mozway 03.07.2024 16:38

@mozway Хорошо, спасибо, но у тебя очень кратко, ура!

ThomasIsCoding 03.07.2024 16:38

Другое возможное решение — использовать панду тмин:

pd.Series(a[::-1]).cummin().iloc[::-1].values

Выход:

array([1, 3, 3, 4, 4])

Другие вопросы по теме