2016-11-30 2 views
2

Wie effektiv ein Array in überlappende Teilfelder schneiden, so dass fürScheibe Array in umgekehrter überlappende Subarrays

>>> N = 5 
>>> L = 2 # could be any, less than N 
>>> x = range(N) 

das erwartete Ergebnis ist

[[1,0],[2,1],[3,2],[4,3]] 

Hier ist, was ich versucht habe:

>>> [ x[i:i-L:-1] for i in range(L-1,len(x)) ] 
[[], [3, 2], [4, 3], [5, 4]] # wrong 

>>> [ x[i:i-L:-1] for i in range(L,len(x)) ] 
[[2, 1], [3, 2], [4, 3]] # wrong 

>>> [ x[i:i-L if i-L >= 0 else None:-1] for i in range(L-1,len(x)) ] 
[[1, 0], [2, 1], [3, 2], [4, 3]] # correct 

Es produziert das gewünschte Ergebnis, aber ist es der beste Weg, um es zu erreichen?

Gibt es einige numpy, itertools Funktionen, die helfen können?

+0

Also, ist die Eingabe eine Liste oder NumPy Array? Ist das erwartete Ergebnis eine Liste oder ein Array? Der Titel sagt 'array', während das Beispiel' range (N) 'ist, das eine Liste erstellt. – Divakar

+0

Danke, ich erwarte, dass es diejenige ist, für die die bessere Lösung existiert. – tarashypka

Antwort

1

Ich gehe davon aus, die Eingabe als NumPy Array. Also, wenn es nicht schon ist, könnten wir es als ein Array mit np.asarray() haben. Daher würden wir mit beginnen: x = np.asarray(input_list), wenn die Eingabe eine Liste ist. Also, mit dem Setup versuchen wir, das Problem zu lösen.

Hier ist ein Ansatz strides verwenden, die das Konzept der views verwendet, das Erstellen von Kopien vermeiden und als solche müssen ziemlich effizient sein -

L = 2 # Row length 
strided = np.lib.stride_tricks.as_strided 
n = x.strides[0] 
out = strided(x[L-1:],shape=(x.size-L+1,L),strides=(n,-n)) 

Beispielläufe -

In [85]: L = 2 

In [86]: strided(x[L-1:],shape=(x.size-L+1,L),strides=(n,-n)) 
Out[86]: 
array([[1, 0], 
     [2, 1], 
     [3, 2], 
     [4, 3]]) 

In [87]: L = 3 

In [88]: strided(x[L-1:],shape=(x.size-L+1,L),strides=(n,-n)) 
Out[88]: 
array([[2, 1, 0], 
     [3, 2, 1], 
     [4, 3, 2]]) 

In [89]: L = 4 

In [90]: strided(x[L-1:],shape=(x.size-L+1,L),strides=(n,-n)) 
Out[90]: 
array([[3, 2, 1, 0], 
     [4, 3, 2, 1]]) 

Hier ist ein weiterer Ansatz broadcasting mit -

L = 2 # Row length 
out = x[np.arange(x.size-L+1)[:,None] + np.arange(L-1,-1,-1)] 
+1

Woher kam 'n'? – user2357112

+0

@ user2357112 Ah danke! Verpasste das früher. – Divakar

1

können Sie einfache Liste verwenden Verständnis

>>> [[x[i+1], x[i]] for i in range(len(x) - 1)] 
[[1, 0], [2, 1], [3, 2], [4, 3]] 

Oder verwenden itertools.izip:

>>> from itertools import izip 
>>> [list(k) for k in izip(x[1:], x)] 
[[1, 0], [2, 1], [3, 2], [4, 3]] 

Ich sehe, dass Sie die Frage aktualisiert, so ist hier generische itertools Weise mit der Verwendung von itertools.izip, itertools.islice und itertools.imap

>>> res = imap(lambda i:islice(reversed(x), i, i+L), xrange(N-L,-1,-1)) 
>>> [list(e) for e in res] 
[[1, 0], [2, 1], [3, 2], [4, 3]] 

Oder sogar reine Generatoren:

>>> res = (reversed(x[i:i+L]) for i in xrange(N-L+1)) 
>>> [list(e) for e in res] 
[[1, 0], [2, 1], [3, 2], [4, 3]] 
+0

Danke, Sie haben eine einfache und elegante Lösung für kleine Subarrays zur Verfügung gestellt. Aber was ist mit dem Fall von 10-Element-Subarrays (auch um 1 Element verschoben)? Also für 'x = range (100)' wird das Ergebnis '[[9,8, .., 0], [10,9, .., 1], .., [99,98, .., 90]] '. – tarashypka

+0

Etwas wie [[x + 1, i, -1] für i im Bereich (len (x) - n + 1)] sollte funktionieren, aber ich kann es nicht atm testen, werde es überprüfen, wenn ich nach Hause komme –

1

Oder mit dem regulären zip

In [158]: x=list(range(5)) 
In [159]: x[1:],x[0:-1] 
Out[159]: ([1, 2, 3, 4], [0, 1, 2, 3]) 
In [160]: list(zip(x[1:],x[0:-1])) 
Out[160]: [(1, 0), (2, 1), (3, 2), (4, 3)] 

oder für Listen

In [161]: [list(i) for i in zip(x[1:],x[0:-1])] 
Out[161]: [[1, 0], [2, 1], [3, 2], [4, 3]] 

Dies wird der Einsatz von zip (eine Liste von Tupeln Herstellung) ist eine Art von transponieren. numpy Arrays auch transponiert leicht:

In [167]: arr=np.array((x[1:],x[:-1])) 
In [168]: arr 
Out[168]: 
array([[1, 2, 3, 4], 
     [0, 1, 2, 3]]) 
In [169]: arr.T.tolist() 
Out[169]: [[1, 0], [2, 1], [3, 2], [4, 3]] 

Bitte beachte, dass ich zwei Kopien der Liste machen musste. Der Ansatz von Divakar stride_tricks ist die einzige Möglichkeit, überlappende "Fenster" ohne Kopieren zu erstellen. Es ist eine fortgeschrittene Methode.

Für kleine Listen würde ich empfehlen, mit den Listenansätzen zu bleiben. Mit der Erstellung von Arrays ist ein Aufwand verbunden.