Самый быстрый способ обнулить низкие значения в массиве?

StackOverflow https://stackoverflow.com/questions/1623849

Вопрос

Итак, допустим, у меня есть 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]
Это было полезно?

Решение

Это типичная работа для 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 модуль.

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

from scipy.stats import threshold
thresholded = threshold(array, 0.5)

:)

В NumPy есть специальный класс MaskedArray, который делает именно это. Вы можете & Quot; mask & Quot; элементы, основанные на любом предварительном условии. Это лучше соответствует вашим потребностям, чем присвоение нулей: при необходимости числовые операции будут игнорировать маскированные значения (например, находить среднее значение).

>>> 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

Использование 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 можно написать без <=> следующим образом:

for i, x in enumerate(a):
    if x < value:
       a[i] = 0

Самый простой способ:

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]

Существует граничное условие, в котором есть два или более равных элемента, которые (в вашем примере) являются третьими по величине элементами. Полученный массив будет содержать этот элемент более одного раза.

Существуют и другие граничные условия, например, len(array) < highCountX. Обработка таких условий остается за разработчиком.

Настроить элементы ниже некоторого порога до нуля очень просто:

array = [ x if x > threshold else 0.0 for x in array ]

(плюс случайный пресс () при необходимости.)

Требование N старших чисел, однако, немного расплывчато. Что, если есть, например, N + 1 равных чисел выше порога? Какой из них обрезать?

Вы можете сначала отсортировать массив, а затем установить пороговое значение для значения N-го элемента:

threshold = sorted(array, reverse=True)[N]
array = [ x if x >= threshold else 0.0 for x in array ]

Примечание. Это решение оптимизировано для удобочитаемости, а не производительности.

Вы можете использовать карту и лямбду, это должно быть достаточно быстро.

new_array = map(lambda x: x if x>y else 0, array)

Используйте кучу .

Это работает вовремя 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]

deletemin работает в куче O(lg(k)) и вставке O(1) или <=> в зависимости от того, какой тип кучи вы используете.

Использование кучи - хорошая идея, как говорит Эгон. Но вы можете использовать функцию 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]
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top