реализация argmax в Python

Как следует реализовать argmax в Python? Он должен быть максимально эффективным, поэтому он должен работать с итерируемыми объектами.

Это может быть реализовано тремя способами:

  • заданная итерация пар возвращает ключ, соответствующий наибольшему значению
  • заданная итерация значений возвращает индекс наибольшего значения
  • учитывая итерацию ключей и функцию f, вернуть ключ с наибольшим f(key)

person Neil G    schedule 23.02.2011    source источник
comment
аргмакс на что? Функция, словарь?   -  person Swiss    schedule 24.02.2011
comment
на двух итерациях, как в математике: argmax_{keys} соответствующие_значения, чтобы он возвращал ключ, соответствующий наибольшему значению.   -  person Neil G    schedule 24.02.2011
comment
Если они являются связанными парами ключ-значение, почему бы не хранить их в ассоциативной структуре данных, такой как словарь?   -  person Swiss    schedule 24.02.2011
comment
Это также может вас заинтересовать: stackoverflow.com/questions/268272/   -  person Swiss    schedule 24.02.2011
comment
Я думаю, вы могли бы это сделать, но мое решение для argmax должно было бы разархивировать dict.items() и повторно заархивировать его как (значения, ключи).   -  person Neil G    schedule 24.02.2011
comment
Круто, я не знал, что Макс может взять ключ.   -  person Neil G    schedule 24.02.2011
comment
@Neil G: Пожалуйста, обновите вопрос, чтобы он был понятен тем, кто еще не знает ответа.   -  person S.Lott    schedule 24.02.2011


Ответы (5)


Я изменил лучшее решение, которое нашел:

# given an iterable of pairs return the key corresponding to the greatest value
def argmax(pairs):
    return max(pairs, key=lambda x: x[1])[0]

# given an iterable of values return the index of the greatest value
def argmax_index(values):
    return argmax(enumerate(values))

# given an iterable of keys and a function f, return the key with largest f(key)
def argmax_f(keys, f):
    return max(keys, key=f)
person Neil G    schedule 23.02.2011
comment
(Я подумал, что этим стоит поделиться, так как я не смог найти его на SO. Если у кого-то есть лучшее решение, поделитесь им!) - person Neil G; 24.02.2011
comment
Я бы рекомендовал использовать обычный zip вместо itertools.izip. Использование itertools не одобряется, если у вас нет веских причин для его использования. - person Swiss; 24.02.2011
comment
Хотя, честно говоря, izip возвращает итератор, а zip возвращает список. Так что izip работает быстрее, если важна скорость. - person Swiss; 24.02.2011
comment
Вы также можете использовать lambda x: x[1] вместо operator.itemgetter(1). Мне кажется, это выглядит немного симпатичнее. - person Swiss; 24.02.2011
comment
@Swiss, как вы заметили, izip в некоторых случаях работает быстрее. Во всяком случае, в python3 izip переименовывается в zip, верно? - person Neil G; 24.02.2011
comment
@Swiss: Я не знаю, откуда вы взяли, что itertools когда-либо осуждалось. Он был добавлен в стандартную библиотеку, чтобы быть легко доступным инструментом. - person ncoghlan; 24.02.2011
comment
@Neil: то, что неодобрительно, использует выражение lambda в качестве правой части оператора присваивания. Вместо этого используйте обычную именованную функцию. - person ncoghlan; 24.02.2011
comment
@ncoghlan, не знал этого. Я их сейчас поменяю, а у вас случайно нет ссылочки? - person Neil G; 24.02.2011
comment
Я не знаю, записано ли это где-нибудь - просто в сценарии присваивания вы страдаете от всех недостатков использования lambda, не получая никаких преимуществ, поэтому именованная функция имеет гораздо больше смысла. - person ncoghlan; 24.02.2011
comment
@ncoghlan Обычно есть более питонические способы делать то же самое, что и itertools. карта и фильтр изначально даже не планировались в Python 3: artima.com /weblogs/viewpost.jsp?thread=98196 - person Swiss; 25.02.2011
comment
@Swiss, вы путаете itertools с functools - карта и сокращение находятся в последнем. - person Elias Dorneles; 22.11.2014

Является ли следующий код быстрым и питоническим способом?

idx_max = max(enumerate(x), key=lambda x:x[1])[0]
person wall-e    schedule 07.12.2011
comment
Хотя это в основном урезанная и некомментированная версия принятого ответа, я нашел ее более полезной, а lambda легче читать, чем operator (даже если вы не используете ее в окончательном решении) - person loopbackbee; 23.07.2015

Мне показалось, что так проще думать об argmax: скажем, мы хотим вычислить argmax(f(y)), где y — элемент из Y. Итак, для каждого y мы хотим вычислить f(y) и получить y с максимальным f(y).

Это определение argmax является общим, в отличие от «данная итерация значений возвращает индекс наибольшего значения» (и это также вполне естественно ИМХО).

И ..барабанная дробь.. Python позволяет сделать именно это с помощью встроенного max:

best_y = max(Y, key=f)

Итак, argmax_f (из принятого ответа) ИМХО излишне сложный и неэффективный - это усложненная версия встроенного max. Все остальные задачи, подобные argmax, должны стать понятными на этом этапе: просто определите правильную функцию f.

person Mikhail Korobov    schedule 14.03.2013

def argmax(lst):
     return lst.index(max(lst))

или аналогично:

argmax = lambda lst: lst.index(max(lst)
person Davoud Taghawi-Nejad    schedule 20.07.2012
comment
Этот подход теоретически неоптимален, поскольку он дважды перебирает список. Тем не менее, это элегантно. - person 1''; 04.11.2014
comment
На самом деле, это быстрее, чем любые другие решения, опубликованные здесь. - person user49117; 28.04.2015

Основано на ответе Нила, но специализировано для функций, которые принимают несколько аргументов.

argmax = lambda keys, func: max(imap(lambda key: (func(*key), key), keys))[1]

Например:

argmax([(5, 2), (3, 3), (2, 5)], pow)
# (2, 5)
person Andrew Clark    schedule 24.02.2011
comment
С пониманием списка вместо imap: max([(func(*key), key) for key in keys]) - person Swiss; 24.02.2011
comment
Генератор почти идентичен, если вы хотите соответствовать скорости imap. max((func(*key), key) для ключа в ключах) - person Swiss; 24.02.2011
comment
@Swiss - форма понимания списка полезна для тех, кто все еще использует старые версии Python, выражения перед генератором. Но вы правы, создание временного списка снижает производительность, просто чтобы вы могли получить от него max(). - person PaulMcG; 24.02.2011