Как получить несколько самых больших значений из списка?
Например у меня есть список:
arr = [1, 200, 400, 2, 100]
Как я могу получить три самых больших значений из списка?
То есть, должно получиться:
[400, 200, 100]
Пробовал функцию max(), но она возвращает только самое максимальное значение - 400.
Ответы (3 шт):
Если у нас есть список размерности list_len и мы хотим найти N наибольших / наименьших элементов, то для случаев когда N << list_len (т.е. когда N значительно меньше list_len) разработчики Python рекомендуют использовать heapq.nlargest() / heapq.nsmallest():
heapq.nlargest(n, iterable, key=None)Return a list with the n largest elements from the dataset defined by iterable. key, if provided, specifies a function of one argument that is used to extract a comparison key from each element in iterable (for example, key=str.lower). Equivalent to: sorted(iterable, key=key, reverse=True)[:n].The latter two functions perform best for smaller values of n. For larger values, it is more efficient to use the
sorted()function. Also, whenn==1, it is more efficient to use the built-inmin()andmax()functions. If repeated usage of these functions is required, consider turning the iterable into an actual heap.
from heapq import nlargest
res = nlargest(3, arr)
результат:
In [18]: res
Out[18]: [400, 200, 100]
Ради интереса сравнил скорости этих сортировок на 100 000 элементах... И нашёл ещё более быстрый способ, кажется:
from heapq import nlargest
import random
import numpy as np
n = 100000
arr = list(range(n))
random.shuffle(arr)
arr_np = np.array(arr)
%timeit res_sorted = sorted(arr, reverse=True)[:3]
%timeit res_heapq = nlargest(3, arr)
%timeit res_np_sort = np.sort(arr_np)[-1:-4:-1]
%timeit res_np_part = -np.partition(-arr_np, 3)[:3]
Результат:
10 loops, best of 3: 41.3 ms per loop
100 loops, best of 3: 4.47 ms per loop
100 loops, best of 3: 8.25 ms per loop
1000 loops, best of 3: 1.09 ms per loop
Обычная сортировка понятно самая медленная - списки в питоне не очень быстрые, а тут приходится сортировать весь список.
nlargest отбирает элементы в 10 (!) раз быстрее. И это логично - ведь тут не нужно переставлять местами элементы или их индексы в огромном списке, а нужно только отобрать самые большие элементы в отдельный список.
Сортировка в Numpy работает в 2 раза медленнее, чем nlargest, но, учитывая, что она создаёт новый numpy.array того же размера, что и исходный, это, наверное, логично.
И, наконец, победитель - функция Numpy.partition, которая возвращает массив, в котором гарантированно отсортировано только заданное число элементов в начале массива. У неё нет сортировки по убыванию и приходится немного извращаться чтобы получить таковую, но работает она в итоге в 4 (!) раза быстрее, чем отбор максимальных элементов через nlargest. Numpy вообще очень сильно оптимизированная библиотека, я не удивлён.
Такие дела.