Frage

So können sagen, dass ich 100.000 float Arrays mit 100 Elementen haben je. Ich brauche die höchste Anzahl von X-Werte, aber nur, wenn sie größer sind als Y. passende Jedes Element, das nicht sollte auf 0 gesetzt werden Was ist der schnellste Weg sein würde, dies in Python zu tun? Ordnung muss beibehalten werden. Die meisten Elemente sind bereits auf 0 gesetzt.

Probenvariablen:

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

erwartetes Ergebnis:

array = [0, .25, 0, .15, .5, 0, 0, 0, 0, 0]
War es hilfreich?

Lösung

Dies ist eine typische Aufgabe für NumPy , die sehr ist schnell für diese Art von Operationen:

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

Nun, wenn Sie nur die highCountX größten Elemente benötigen, können Sie sogar „vergessen“ die kleinen Elemente (statt sie auf 0 setzen ordnen und sortieren) und nur sortiert die Liste der großen Elemente:

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

Natürlich das gesamte Array Sortierung, wenn Sie nur einige Elemente brauchen nicht optimal sein könnte. Je nach Bedarf, können Sie den Standard heapq Modul zu berücksichtigen.

Andere Tipps

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

:)

Es gibt eine spezielle Klasse MaskedArray in NumPy, die genau das tut. Sie können „Maske“ Elemente auf jeder Voraussetzung basiert. Diese besser repräsentieren Ihren Bedarf als Zuweisung Nullen. Numpy Operationen maskierte Werte ignorieren, wenn entsprechende (zum Beispiel Mittelwert zu finden)

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

Als added Vorteil, maskierte Arrays sind in matplotlib Visualisierungsbibliothek unterstützt, wenn Sie diese brauchen.

Docs auf maskierten Arrays in numpy

Mit 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

Wo partial_sort könnte sein:

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] 

Der Ausdruck a[a<value] = 0 kann ohne numpy wie folgt geschrieben werden:

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

Der einfachste Weg wäre:

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]

In Stücke, dies wählt alle Elemente größer ist als lowValY:

[x for x in array if x > lowValY]

Dieses Array enthält nur die Anzahl von Elementen größer als die Schwelle. Dann ist es so die größten Werte sind zu Beginn Sortierung:

sorted(..., reverse=True)

Dann wird eine Liste Index nimmt den Schwellenwert für die oberen highCountX Elemente:

sorted(...)[highCountX-1]

Schließlich wird das Original-Array ausgefüllt andere Liste Verständnis mit:

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

Es gibt eine Randbedingung, wo es zwei oder mehr gleichen Elemente, die (in Ihrem Beispiel) sind die 3.en höchsten Elemente. Das resultierende Array enthält das Element mehr als einmal.

Es gibt auch andere Randbedingungen als auch, wie wenn len(array) < highCountX. solche Bedingungen Handhabung wird dem Implementierer überlassen.

Einstellungen Elemente unter einem Schwellenwert Null ist einfach:

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

(plus die gelegentliche abs (), falls erforderlich.)

Die Anforderung der N höchsten Zahlen ist etwas vage, aber. Was, wenn es zum Beispiel N + 1 zu gleichen Teilen über dem Schwellenwert? Die man kürzen?

Sie können das Array sortieren zuerst, dann stellen Sie den Schwellenwert auf den Wert des N-ten Element:

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

. Hinweis: Diese Lösung zur besseren Lesbarkeit nicht die Leistung optimiert ist

Sie Karte und Lambda verwenden können, sollte es schnell genug sein.

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

Verwenden Sie einen Haufen .

Das funktioniert in der Zeit 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 arbeitet in Haufen O(lg(k)) und Einfügen O(lg(k)) oder O(1) je nachdem, welchen Haufen Typ Sie verwenden.

einen Haufen ist eine gute Idee, wie egon sagt. Aber Sie können die heapq.nlargest Funktion auf einigen Aufwand zu reduzieren:

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]
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top