2016-04-27 7 views
14

Ich habe einen langen boolean-Array:Wie identifiziere ich Folgen von Werten in einem booleschen Array?

bool_array = [ True, True, True, True, True, False, False, False, False, False, True, True, True, False, False, True, True, True, True, False, False, False, False, False, False, False ] 

Ich muß, um herauszufinden, wo die Werte Flips, das heißt die Adressen, in denen Sequenzen von True und False beginnen. In diesem speziellen Fall würde ich

index = [0, 5, 10, 13, 15, 19, 26] 

Gibt es eine einfache Art und Weise zu tun, ohne manuell Looping überprüfen jedes i-te Element mit der (i + 1) zu bekommen? wo

Antwort

15

Als effizientere Methode für große Datenmengen können Sie in Python 3.X accumulate und groupby Funktion von itertools Modul verwenden.

>>> from itertools import accumulate, groupby 
>>> [0] + list(accumulate(sum(1 for _ in g) for _,g in groupby(bool_array))) 
[0, 5, 10, 13, 15, 19, 26] 

die Logik hinter dem Code:

Dieser Code, stuft die sequentiellen doppelten Elemente unter Verwendung groupby() Funktion, schleift dann über den Iterator durch groupby() zurückgegeben, die Paare von Tasten enthält (die wir entkommen es unter der Zeile statt einer wegwerfbaren Variable verwendet) und diese kategorisierten Iteratoren.

>>> [list(g) for _, g in groupby(bool_array)] 
[[True, True, True, True, True], [False, False, False, False, False], [True, True, True], [False, False], [True, True, True, True], [False, False, False, False, False, False, False]] 

Also alles, was wir brauchen, ist die Länge dieser Iteratoren Berechnung und jede Länge mit seiner früheren Länge summieren, um den Index des ersten Elements zu erhalten, das genau ist, wo das Element geändert wird, das ist genau das, was das accumulate() Funktion ist für.

In Numpy können Sie die folgende Methode verwenden:

In [19]: np.where(arr[1:] - arr[:-1])[0] + 1 
Out[19]: array([ 5, 10, 13, 15, 19]) 
# With leading and trailing indices 
In [22]: np.concatenate(([0], np.where(arr[1:] - arr[:-1])[0] + 1, [arr.size])) 
Out[22]: array([ 0, 5, 10, 13, 15, 19, 26]) 
+2

Ich würde sagen, dass die Absicht dieses Codes ziemlich undurchsichtig ist, sogar für ziemlich qualifizierte Leute, leider. 'itertools' ist großartig, aber es ist fast eine Sprache für sich. – PythonNut

10

Dies wird Ihnen sagen:

>>> import numpy as np 
>>> np.argwhere(np.diff(bool_array)).squeeze() 
array([ 4, 9, 12, 14, 18]) 

np.diff die Differenz zwischen jedem Element und dem nächsten berechnet. Bei Booleschen Werten werden die Werte im Wesentlichen als Ganzzahlen interpretiert (0: Falsch, ungleich Null: Wahr), sodass Unterschiede als +1 oder -1-Werte angezeigt werden, die dann wieder in Boolesche Werte umgewandelt werden (True bei einer Änderung).

Die np.argwhere Funktion sagt Ihnen dann, wo die Werte wahr sind --- die jetzt sind die Änderungen.

+3

das ist die "richtige" Antwort. –

+1

Kühl. Das war, was ich suchte. Allerdings habe ich die Antwort "accumulate" so richtig markiert, wie sie für ein großes Array schneller war. – saud

5

Mit zip und enumerate können Sie

>>> [i for i,(m,n) in enumerate(zip(bool_array[:-1],bool_array[1:])) if m!=n] 
[4, 9, 12, 14, 18] 

Jetzt tun, dass Sie [4, 9, 12, 14, 18] haben, können Sie

>>> [0]+[i+1 for i in [4, 9, 12, 14, 18]]+[len(bool_array)] 
[0, 5, 10, 13, 15, 19, 26] 

Ihre Ausgabe zu erreichen.


die Logik hinter dem Code:

  • zip in beiden Iteratoren nimmt und gibt eine Sequenz von zwei Elementen. Wir übergeben die gleiche Liste für beide Iteratoren beginnend mit dem ersten Element und beginnend mit dem zweiten Element. Somit erhalten wir eine Liste von benachbarten Zahlen
  • enumerate Ihnen eine Folge von Indizes und den Wert des Iterators gibt.
  • Jetzt wickeln wir es in einer Liste Verständnis. Wenn der RV-Wert nicht gleich ist, wir den Index

Eine weiterer Schritt Prozedur zurückzukehren

>>> [i for i,(m,n) in enumerate(zip([2]+bool_array,bool_array+[2])) if m!=n] 
[0, 5, 10, 13, 15, 19, 26] 

Hier sind uns bewusst [2] in die Liste der Einführung Dies liegt daran, die erste und Die letzten Werte sind immer unterschiedlich ([2] ist nie in der Liste vorhanden). Daher werden wir diese Indizes direkt erhalten.

+0

schnell für kleinere Listen. –

+2

'answer ++': Ich freue mich, eine Antwort zu sehen, die nicht auf 'itertools' und/oder' numpy' angewiesen ist. – cat

+0

Sie können den zweiten Schritt überspringen, wenn Sie einen Wert an der Vorderseite hinzufügen, anstatt einen zu löschen. – alexis

Verwandte Themen