2009-10-26 10 views
34

Więc powiedzmy, że mam 100 000 tablic zmiennopozycyjnych zawierających po 100 elementów. Potrzebuję najwyższą liczbę X wartości, ale tylko jeśli są one większe niż Y. Każdy element nie pasujący do tego powinien być ustawiony na 0. Jaka byłaby najszybsza metoda w Pythonie? Zamówienie musi zostać utrzymane. Większość elementów jest już ustawiony na 0.Najszybszy sposób na wyzerowanie niskich wartości w tablicy?

przykładowych zmiennych:

array = [.06, .25, 0, .15, .5, 0, 0, 0.04, 0, 0] 
highCountX = 3 
lowValY = .1 

oczekiwany rezultat:

array = [0, .25, 0, .15, .5, 0, 0, 0, 0, 0] 
+0

Co jest HightCountX jest za? –

+0

highCountX to maksymalna liczba niezerowych elementów, które chcę wprowadzić w tablicy – David

+0

Jeśli był to 2, oczekiwany wynik byłby następujący: [0, 0, 0, .15, .5, 0, 0, 0, 0, 0] - highCountX ogranicza liczbę niezerowych elementów w wyniku. – Abgan

Odpowiedz

73

Jest to typowe zadanie dla NumPy, który jest bardzo szybki dla tych rodzajów operacji:

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 

Teraz, jeśli potrzebujesz tylko highCountX największe elementy, można nawet „zapomnieć” małe elementy (zamiast ustawiać je na 0 i ich sortowania) i tylko posortować listę dużych elementów:

array_np = numpy.asarray(array) 
print numpy.sort(array_np[array_np >= lowValY])[-highCountX:] 

oczywiście sortowania cały wachlarz jeśli potrzebujesz tylko kilka elementów może nie być optymalna. W zależności od potrzeb możesz rozważyć standardowy moduł heapq.

+5

Przyjemnie ... używanie odpowiednich bibliotek może zabrać Cię naprawdę daleko :-) – Abgan

+0

Ciągle bierzemy się do tego numeru, zgaduję, że muszę to sprawdzić :) Dzięki za pomoc (wszyscy). – David

+0

@David NumPy naprawdę wypełnia potrzebę. Proponuję zacząć od samouczka, do którego się przyłączyłem: jest to prawdopodobnie najszybszy sposób na przyspieszenie korzystania z NumPy i poznanie jego najważniejszych koncepcji. – EOL

5

Najprostszym sposobem byłoby:

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] 

w kawałkach, to wybiera wszystkie elementy większe niż lowValY:

[x for x in array if x > lowValY] 

Ta tablica zawiera tylko liczbę elementów większą od progu. Następnie sortowania go więc największymi wartościami są na początku:

sorted(..., reverse=True) 

następnie indeks lista trwa próg najlepszych highCountX elementów:

sorted(...)[highCountX-1] 

Wreszcie, oryginalna tablica jest wypełniony przy użyciu innego listowego:

[x if x >= topX else 0 for x in array] 

jest warunek brzegowy gdzie istnieją dwa lub więcej równych elementów, które (w swoim przykładzie) są 3rd najwyższe elementy. Wynikowa tablica będzie zawierać ten element więcej niż jeden raz.

Istnieją również inne warunki brzegowe, na przykład len(array) < highCountX. Postępowanie z takimi warunkami pozostawia się realizatorowi.

+1

Możesz użyć x dla x w tablicy, jeśli x> lowValY zamiast [x dla x w tablicy, jeśli x> lowValY] by wyliczyć tylko nad oryginalną tablicą bez jej kopiowania (jeśli oryginalne dane są dość duże, to może być dobrze). – Abgan

+1

To prawda. Jednak "sorted()" prawdopodobnie będzie potrzebował całej listy. –

+0

Heh, 3 razy szybciej niż mój kod noob, ale potrzebowałbym tych samych elementów, aby utrzymać limit highCountX. Macierze powinny mieć od 20 do 200 elementów ... w rzeczywistości są segmentami większej macierzy, którą przetwarzam w porcjach. Dzięki za pomoc do tej pory. – David

2

ustawień elementów poniżej pewnej wartości progowej do zera jest łatwe: (. Oraz okazjonalne ABS(), w razie potrzeby)

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

Wymóg N najwyższych liczb jest nieco niejasna, jakkolwiek. Co jeśli są np. N + 1 równe liczby powyżej progu? Który z nich skrócić?

Można posortować tablicę, potem ustawić próg wartości elementu n-ty:

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

Uwaga: To rozwiązanie jest zoptymalizowany pod kątem czytelności nie wydajności.

+0

w tym przypadku nie ma znaczenia, który z nich jest obcięty ... ważniejsze jest to, że highCountX jest śledzony – David

6

Korzystanie 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 

Gdzie partial_sort mogą być:

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] 

Wyrażenie a[a<value] = 0 może być napisany bez numpy następująco:

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

Można używać map i lambda powinno być szybkie e nough.

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

Użyj heap.

To działa w czasie 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 pracuje w stercie O(lg(k)) i wkładania O(lg(k)) lub O(1) zależności od typu sterty używasz.

+0

nie przetestował składni kodu ... – Egon

7

Istnieje specjalna klasa MaskedArray w NumPy, która robi dokładnie to. Możesz "maskować" elementy w oparciu o dowolny warunek wstępny. To lepiej reprezentuje twoją potrzebę niż przypisywanie zer: operacje numpy zignorują maskowane wartości, gdy jest to odpowiednie (na przykład, znalezienie wartości średniej).

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

Jako addded korzyści, zamaskowanych tablice są dobrze obsługiwane w matplotlib wizualizacji biblioteki, jeśli to potrzebne.

Docs on masked arrays in numpy

0

Korzystanie sterty jest dobrym pomysłem, jak mówi Egon. Ale można użyć funkcji heapq.nlargest aby obniżyć pewnym wysiłkiem:

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] 
+0

Podoba mi się to domowe rozwiązanie, które wykorzystuje tylko standardowe moduły. Należy go jednak zaktualizować tak, aby rzeczywiście zwracał największe elementy highCountX (jeśli wiele elementów w tablicy ma wartość 'threshold', ostateczna tablica ma zbyt wiele niezerowych elementów). – EOL

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

:)

Powiązane problemy