Самый быстрый способ обнулить низкие значения в массиве?
Итак, скажем, у меня есть 100 000 массивов с плавающей запятой по 100 элементов. Мне нужно наивысшее количество X значений, но только если они больше Y. Любой элемент, не соответствующий этому, должен быть установлен в 0. Какой будет самый быстрый способ сделать это в Python? Заказ должен быть сохранен. Большинство элементов уже установлены в 0.
выборочные переменные:
array = [.06, .25, 0, .15, .5, 0, 0, 0.04, 0, 0]
highCountX = 3
lowValY = .1
ожидаемый результат:
array = [0, .25, 0, .15, .5, 0, 0, 0, 0, 0]
Ответы
Ответ 1
Это типичная работа для NumPy, которая выполняется очень быстро для таких операций:
array_np = numpy.asarray(array)
low_values_flags = array_np < lowValY # Where values are low
array_np[low_values_flags] = 0 # All low values set to 0
Теперь, если вам нужны только самые большие элементы highCountX, вы можете даже "забыть" маленькие элементы (вместо того, чтобы устанавливать их в 0 и сортировать их) и сортировать только список больших элементов:
array_np = numpy.asarray(array)
print numpy.sort(array_np[array_np >= lowValY])[-highCountX:]
Конечно, сортировка всего массива, если вам нужно всего несколько элементов, может быть неоптимальной. В зависимости от ваших потребностей, вы можете рассмотреть стандартный модуль heapq.
Ответ 2
from scipy.stats import threshold
thresholded = threshold(array, 0.5)
:)
Ответ 3
В NumPy есть специальный класс MaskedArray, который делает именно это. Вы можете "маскировать" элементы на основе любых предварительных условий. Это лучше отражает ваши потребности, чем назначение нулей: операции numpy будут игнорировать маскированные значения, когда это необходимо (например, найти среднее значение).
>>> from numpy import ma
>>> x = ma.array([.06, .25, 0, .15, .5, 0, 0, 0.04, 0, 0])
>>> x1 = ma.masked_inside(0, 0.1) # mask everything in 0..0.1 range
>>> x1
masked_array(data = [-- 0.25 -- 0.15 0.5 -- -- -- -- --],
mask = [ True False True False False True True True True True],
fill_value = 1e+20)
>>> print x.filled(0) # Fill with zeroes
[ 0 0.25 0 0.15 0.5 0 0 0 0 0 ]
В качестве дополнительного преимущества маскированные массивы хорошо поддерживаются в библиотеке визуализации matplotlib, если вам это нужно.
Документы для маскированных массивов в numpy
Ответ 4
Использование numpy
:
# assign zero to all elements less than or equal to `lowValY`
a[a<=lowValY] = 0
# find n-th largest element in the array (where n=highCountX)
x = partial_sort(a, highCountX, reverse=True)[:highCountX][-1]
#
a[a<x] = 0 #NOTE: it might leave more than highCountX non-zero elements
# . if there are duplicates
Где partial_sort
может быть:
def partial_sort(a, n, reverse=False):
#NOTE: in general it should return full list but in your case this will do
return sorted(a, reverse=reverse)[:n]
Выражение a[a<value] = 0
можно записать без numpy
следующим образом:
for i, x in enumerate(a):
if x < value:
a[i] = 0
Ответ 5
Самый простой способ:
topX = sorted([x for x in array if x > lowValY], reverse=True)[highCountX-1]
print [x if x >= topX else 0 for x in array]
В кусках это выбирает все элементы, превышающие lowValY
:
[x for x in array if x > lowValY]
Этот массив содержит только количество элементов, большее порога. Затем, сортируя его так, чтобы самые большие значения были в начале:
sorted(..., reverse=True)
Затем индекс списка принимает пороговое значение для верхних элементов highCountX
:
sorted(...)[highCountX-1]
Наконец, исходный массив заполняется с использованием другого понимания списка:
[x if x >= topX else 0 for x in array]
Существует граничное условие, в котором есть два или более одинаковых элемента, которые (в вашем примере) являются 3-м высшим элементом. Результирующий массив будет содержать этот элемент более одного раза.
Существуют и другие граничные условия, например, если len(array) < highCountX
. Обработка таких условий предоставляется разработчику.
Ответ 6
Элементы настроек ниже некоторого порогового значения равны нулю:
array = [ x if x > threshold else 0.0 for x in array ]
(плюс случайный абс(), если необходимо.)
Однако требование N наивысших чисел немного расплывчато. Что, если есть, например, N + 1 равных чисел выше порога? Какой из них усекать?
Сначала вы можете отсортировать массив, а затем установить пороговое значение для элемента Nth:
threshold = sorted(array, reverse=True)[N]
array = [ x if x >= threshold else 0.0 for x in array ]
Примечание. Это решение оптимизировано для удобства чтения.
Ответ 7
Вы можете использовать карту и лямбду, она должна быть достаточно быстрой.
new_array = map(lambda x: x if x>y else 0, array)
Ответ 8
Используйте heap.
Это работает со временем O(n*lg(HighCountX))
.
import heapq
heap = []
array = [.06, .25, 0, .15, .5, 0, 0, 0.04, 0, 0]
highCountX = 3
lowValY = .1
for i in range(1,highCountX):
heappush(heap, lowValY)
heappop(heap)
for i in range( 0, len(array) - 1)
if array[i] > heap[0]:
heappush(heap, array[i])
min = heap[0]
array = [x if x >= min else 0 for x in array]
dieemin работает в куче O(lg(k))
и вставке O(lg(k))
или O(1)
в зависимости от используемого типа кучи.
Ответ 9
Использование кучи - хорошая идея, как говорит эгон. Но вы можете использовать функцию heapq.nlargest
, чтобы сократить некоторые усилия:
import heapq
array = [.06, .25, 0, .15, .5, 0, 0, 0.04, 0, 0]
highCountX = 3
lowValY = .1
threshold = max(heapq.nlargest(highCountX, array)[-1], lowValY)
array = [x if x >= threshold else 0 for x in array]