Iteratore di finestre scorrevoli o scorrevoli?


151

Ho bisogno di una finestra mobile (ovvero finestra scorrevole) ripetibile su una sequenza / iteratore / generatore. L'iterazione Python predefinita può essere considerata un caso speciale, in cui la lunghezza della finestra è 1. Attualmente sto usando il seguente codice. Qualcuno ha un metodo più Pythonic, meno dettagliato o più efficiente per farlo?

def rolling_window(seq, window_size):
    it = iter(seq)
    win = [it.next() for cnt in xrange(window_size)] # First window
    yield win
    for e in it: # Subsequent windows
        win[:-1] = win[1:]
        win[-1] = e
        yield win

if __name__=="__main__":
    for w in rolling_window(xrange(6), 3):
        print w

"""Example output:

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

3
Se stai cercando di eseguire un qualche tipo di operazione su ogni finestra mentre esegui l'iterazione (ad es. sum()O max()), vale la pena ricordare che esistono algoritmi efficienti per calcolare il nuovo valore per ogni finestra in tempo costante (indipendentemente dalle dimensioni della finestra). Ho raccolto alcuni di questi algoritmi insieme in una libreria Python: rolling .
Alex Riley,

Risposte:


123

Ce n'è uno in una vecchia versione dei documenti Python con itertoolsesempi :

from itertools import islice

def window(seq, n=2):
    "Returns a sliding window (of width n) over data from the iterable"
    "   s -> (s0,s1,...s[n-1]), (s1,s2,...,sn), ...                   "
    it = iter(seq)
    result = tuple(islice(it, n))
    if len(result) == n:
        yield result
    for elem in it:
        result = result[1:] + (elem,)
        yield result

Quello dei documenti è un po 'più conciso e usa itertoolscon maggior effetto immagino.


2
Bella risposta, ma (e so che stai solo riproducendo la ricetta come collegata), mi chiedo perché la dimensione della finestra predefinita dovrebbe essere 2? Dovrebbe avere un valore predefinito?
SingleNegationElimination

19
@TakenMacGuy: Non so quale sia l'autore del ragionamento di quella ricetta, ma sceglierei anche 2. 2 è la dimensione della finestra utile più piccola (altrimenti stai solo iterando e non hai bisogno della finestra), ed è anche comune avere bisogno di conoscere l'elemento precedente (o successivo), probabilmente più di ogni altro n.
kindall

27
Qualcuno sa perché questo esempio è stato rimosso dai documenti? C'era qualcosa che non andava, o c'è un'alternativa più semplice adesso?
mercoledì


2
Quando si entra nel for elem in itciclo?
Glassjawed

47

Questo sembra fatto su misura per un collections.dequedato che essenzialmente hai un FIFO (aggiungi a un'estremità, rimuovi dall'altra). Tuttavia, anche se usi un listnon dovresti tagliare due volte; invece, dovresti probabilmente solo pop(0)dalla lista e append()dal nuovo elemento.

Ecco un'implementazione ottimizzata basata su deque modellata sul tuo originale:

from collections import deque

def window(seq, n=2):
    it = iter(seq)
    win = deque((next(it, None) for _ in xrange(n)), maxlen=n)
    yield win
    append = win.append
    for e in it:
        append(e)
        yield win

Nei miei test batte facilmente tutto il resto pubblicato qui la maggior parte delle volte, anche se la teeversione di Pillmuncher lo batte per grandi iterabili e piccole finestre. Su finestre più grandi, dequetira di nuovo avanti a tutta velocità.

L'accesso ai singoli elementi nel dequepuò essere più veloce o più lento che con elenchi o tuple. (Gli oggetti vicino all'inizio sono più veloci, o gli oggetti vicino alla fine se usi un indice negativo.) Inserisco a sum(w)nel corpo del mio ciclo; questo gioca alla forza del deque (iterare da un oggetto al successivo è veloce, quindi questo ciclo ha funzionato un 20% più veloce del prossimo metodo più veloce, il pillmuncher). Quando l'ho modificato per cercare individualmente e aggiungere elementi in una finestra di dieci, le tabelle sono cambiate e il teemetodo è stato del 20% più veloce. Sono stato in grado di recuperare un po 'di velocità utilizzando gli indici negativi per gli ultimi cinque termini nell'aggiunta, ma teeero ancora un po' più veloce. Nel complesso, stimerei che uno dei due sia molto veloce per la maggior parte degli usi e se hai bisogno di un po 'più di prestazioni, profila e scegli quello che funziona meglio.


11
yield windovrebbe essere yield tuple(win)o yield list(win)per impedire la restituzione di un iteratore di riferimenti allo stesso dequeoggetto.
Joel Cornett,

1
Ho inviato questo a PyPI . Installa con pip install sliding_windowed esegui con from sliding_window import window.
Thomas Levine,

1
Sei scioccato se pensi che list(window(range(10)))dovrebbe produrre qualcosa del tipo [[0,1], [1,2], [2,3], ...]
Paul,

1
Ovviamente non lo farà; avresti bisogno di fare qualcosa di simile list(list(x) for x in window(range(10)))o di aggiungerlo all'iteratore. Per alcune applicazioni questo avrà importanza, per altre no, e dato che stavo andando alla velocità, non ho scelto e ho messo l'onere sul chiamante per copiare la finestra, se necessario.
kindall

1
Se si aggiunge il necessario tuple()prima della resa, questo metodo non presenta alcun vantaggio rispetto agli altri.
kawing-chiu,

35

Mi piace tee():

from itertools import tee, izip

def window(iterable, size):
    iters = tee(iterable, size)
    for i in xrange(1, size):
        for each in iters[i:]:
            next(each, None)
    return izip(*iters)

for each in window(xrange(6), 3):
    print list(each)

dà:

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

Dai miei rapidi timeittest, questo è molto più lento di quello di Daniel DePaolo (con un rapporto di circa 2: 1) e non sembra molto "più bello".
David B.

@ David B .: Nella mia scatola è solo circa l'8% più lento di quello di Daniel DePaolo.
pillmuncher,

@pillmuncher: Python 2.7 o 3.x? Stavo usando 2.7. Il rapporto è anche abbastanza sensibile al valore di size. Se lo aumenti (ad esempio, se l'iterabile è lungo 100000 elementi, rendi la dimensione della finestra 1000), potresti vedere un aumento.
David B.

2
@ David B .: Quello che dici ha senso. Nel mio codice il tempo di installazione itersè O (dimensione!), E chiamare next()molte volte (in izip()) probabilmente richiede molto più tempo che copiare due volte una tupla. Stavo usando Python 2.6.5, BTW.
Pillmuncher,

@pillmuncher: Intendi, il tempo di installazione itersè O (dimensione ^ 2), giusto?
David B.

20

Ecco una generalizzazione che aggiunge il supporto per step, fillvalueparametri:

from collections import deque
from itertools import islice

def sliding_window(iterable, size=2, step=1, fillvalue=None):
    if size < 0 or step < 1:
        raise ValueError
    it = iter(iterable)
    q = deque(islice(it, size), maxlen=size)
    if not q:
        return  # empty iterable or size == 0
    q.extend(fillvalue for _ in range(size - len(q)))  # pad to size
    while True:
        yield iter(q)  # iter() to avoid accidental outside modifications
        try:
            q.append(next(it))
        except StopIteration: # Python 3.5 pep 479 support
            return
        q.extend(next(it, fillvalue) for _ in range(step - 1))

Produce in pezzi sizepezzi alla volta rotolando le stepposizioni per iterazione riempiendo ogni pezzo con fillvaluese necessario. Esempio per size=4, step=3, fillvalue='*':

 [a b c d]e f g h i j k l m n o p q r s t u v w x y z
  a b c[d e f g]h i j k l m n o p q r s t u v w x y z
  a b c d e f[g h i j]k l m n o p q r s t u v w x y z
  a b c d e f g h i[j k l m]n o p q r s t u v w x y z
  a b c d e f g h i j k l[m n o p]q r s t u v w x y z
  a b c d e f g h i j k l m n o[p q r s]t u v w x y z
  a b c d e f g h i j k l m n o p q r[s t u v]w x y z
  a b c d e f g h i j k l m n o p q r s t u[v w x y]z
  a b c d e f g h i j k l m n o p q r s t u v w x[y z * *]

Per un esempio di caso d'uso del stepparametro, vedere Elaborazione efficiente di un grande file .txt in python .


17

C'è una libreria che fa esattamente ciò di cui hai bisogno:

import more_itertools
list(more_itertools.windowed([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15],n=3, step=3))

Out: [(1, 2, 3), (4, 5, 6), (7, 8, 9), (10, 11, 12), (13, 14, 15)]

step=3dovrebbe effettivamente essere rimosso per soddisfare la richiesta del PO:list(more_itertools.windowed(range(6), 3))
user3780389

10

Solo un rapido contributo.

Poiché gli attuali documenti di Python non hanno "finestra" negli esempi itertool (cioè, in fondo a http://docs.python.org/library/itertools.html ), ecco uno snippet basato sul codice per grouper che è uno degli esempi forniti:

import itertools as it
def window(iterable, size):
    shiftedStarts = [it.islice(iterable, s, None) for s in xrange(size)]
    return it.izip(*shiftedStarts)

Fondamentalmente, creiamo una serie di iteratori affettati, ognuno con un punto di partenza un punto più avanti. Quindi, li comprimiamo insieme. Nota, questa funzione restituisce un generatore (non è direttamente un generatore stesso).

Proprio come le versioni degli elementi accodanti e degli avanzatori-iteratori sopra, le prestazioni (ovvero, la cosa migliore) variano a seconda delle dimensioni dell'elenco e delle dimensioni della finestra. Mi piace questo perché è un liner (potrebbe essere un liner, ma preferisco i concetti di denominazione).

Si scopre che il codice sopra è sbagliato . Funziona se il parametro passato a iterable è una sequenza ma non se è un iteratore. Se si tratta di un iteratore, lo stesso iteratore viene condiviso (ma non teeed) tra le chiamate islice e questo interrompe le cose in modo non corretto.

Ecco qualche codice fisso:

import itertools as it
def window(iterable, size):
    itrs = it.tee(iterable, size)
    shiftedStarts = [it.islice(anItr, s, None) for s, anItr in enumerate(itrs)]
    return it.izip(*shiftedStarts)

Inoltre, un'altra versione per i libri. Invece di copiare un iteratore e quindi far avanzare le copie più volte, questa versione crea copie a coppie di ogni iteratore mentre spostiamo la posizione iniziale in avanti. Pertanto, l'iteratore t fornisce sia all'iteratore "completo" il punto iniziale at che la base per la creazione dell'iteratore t + 1:

import itertools as it
def window4(iterable, size):
    complete_itr, incomplete_itr = it.tee(iterable, 2)
    iters = [complete_itr]
    for i in xrange(1, size):
        incomplete_itr.next()
        complete_itr, incomplete_itr = it.tee(incomplete_itr, 2)
        iters.append(complete_itr)
    return it.izip(*iters)

9

Solo per mostrare come combinare le itertoolsricette , sto estendendo la pairwisericetta il più direttamente possibile nella windowricetta usando la consumericetta:

def consume(iterator, n):
    "Advance the iterator n-steps ahead. If n is none, consume entirely."
    # Use functions that consume iterators at C speed.
    if n is None:
        # feed the entire iterator into a zero-length deque
        collections.deque(iterator, maxlen=0)
    else:
        # advance to the empty slice starting at position n
        next(islice(iterator, n, n), None)

def window(iterable, n=2):
    "s -> (s0, ...,s(n-1)), (s1, ...,sn), (s2, ..., s(n+1)), ..."
    iters = tee(iterable, n)
    # Could use enumerate(islice(iters, 1, None), 1) to avoid consume(it, 0), but that's
    # slower for larger window sizes, while saving only small fixed "noop" cost
    for i, it in enumerate(iters):
        consume(it, i)
    return zip(*iters)

La windowricetta è la stessa di pairwise, sostituisce semplicemente il singolo elemento "consuma" sul secondo teeiteratore con consumi progressivamente crescenti sugli n - 1iteratori. L'utilizzo consumeanziché il wrapping di ogni iteratore isliceè leggermente più veloce (per iterable sufficientemente grandi) poiché si paga solo il islicesovraccarico di wrapping durante la consumefase, non durante il processo di estrazione di ogni valore con finestra (quindi è limitato n, non dal numero di elementi in iterable).

Per quanto riguarda le prestazioni, rispetto ad alcune altre soluzioni, questo è abbastanza buono (e migliore di qualsiasi altra soluzione che ho testato in scala). Testato su Python 3.5.0, Linux x86-64, usando la ipython %timeitmagia.

kindall è la dequesoluzione , ottimizzata per le prestazioni / correttezza utilizzando isliceinvece di un'espressione del generatore home-roll e testando la lunghezza risultante in modo che non produca risultati quando l'iterabile è più corto della finestra, oltre a passare il maxlendel dequeposizionalmente anziché per parola chiave (fa una differenza sorprendente per input più piccoli):

>>> %timeit -r5 deque(windowkindall(range(10), 3), 0)
100000 loops, best of 5: 1.87 μs per loop
>>> %timeit -r5 deque(windowkindall(range(1000), 3), 0)
10000 loops, best of 5: 72.6 μs per loop
>>> %timeit -r5 deque(windowkindall(range(1000), 30), 0)
1000 loops, best of 5: 71.6 μs per loop

Come la precedente soluzione kindall adattata, ma con ciascuna yield winmodifica in yield tuple(win)modo da memorizzare i risultati dal generatore funziona senza che tutti i risultati memorizzati siano realmente una vista del risultato più recente (tutte le altre soluzioni ragionevoli sono sicure in questo scenario) e si aggiungono tuple=tuplealla definizione della funzione per spostare l'uso di tupleda Bin LEGBa L:

>>> %timeit -r5 deque(windowkindalltupled(range(10), 3), 0)
100000 loops, best of 5: 3.05 μs per loop
>>> %timeit -r5 deque(windowkindalltupled(range(1000), 3), 0)
10000 loops, best of 5: 207 μs per loop
>>> %timeit -r5 deque(windowkindalltupled(range(1000), 30), 0)
1000 loops, best of 5: 348 μs per loop

consumesoluzione di base mostrata sopra:

>>> %timeit -r5 deque(windowconsume(range(10), 3), 0)
100000 loops, best of 5: 3.92 μs per loop
>>> %timeit -r5 deque(windowconsume(range(1000), 3), 0)
10000 loops, best of 5: 42.8 μs per loop
>>> %timeit -r5 deque(windowconsume(range(1000), 30), 0)
1000 loops, best of 5: 232 μs per loop

Uguale consume, ma inlining elsecaso consumedi chiamata di funzione evita e n is Noneprova per ridurre runtime, particolarmente per piccoli ingressi dove l'overhead configurazione è una parte significativa del lavoro:

>>> %timeit -r5 deque(windowinlineconsume(range(10), 3), 0)
100000 loops, best of 5: 3.57 μs per loop
>>> %timeit -r5 deque(windowinlineconsume(range(1000), 3), 0)
10000 loops, best of 5: 40.9 μs per loop
>>> %timeit -r5 deque(windowinlineconsume(range(1000), 30), 0)
1000 loops, best of 5: 211 μs per loop

(Nota a margine: una variante pairwiseche utilizza teeripetutamente l'argomento 2 per creare teeoggetti nidificati , quindi ogni dato iteratore viene avanzato solo una volta, non consumato in modo indipendente un numero crescente di volte, simile alla risposta di MrDrFenner è simile a non in linea consumee più lento di quello integrato consumein tutti i test, quindi ho omesso quei risultati per brevità).

Come puoi vedere, se non ti interessa la possibilità che il chiamante abbia bisogno di memorizzare i risultati, la mia versione ottimizzata della soluzione di kindall vince la maggior parte del tempo, tranne nel "caso iterabile grande, di dimensioni ridotte" (dove consumevince la linea ); si degrada rapidamente all'aumentare della dimensione iterabile, mentre non diminuisce affatto all'aumentare della dimensione della finestra (ogni altra soluzione si degrada più lentamente all'aumentare della dimensione iterabile, ma diminuisce anche all'aumentare della dimensione della finestra). Può anche essere adattato al caso "bisogno di tuple" avvolgendolo map(tuple, ...), che funziona in modo leggermente più lento rispetto al mettere la tupling nella funzione, ma è banale (richiede 1-5% in più) e ti consente di mantenere la flessibilità di correre più veloce quando puoi tollerare ripetutamente la restituzione dello stesso valore.

Se hai bisogno di sicurezza contro la memorizzazione dei ritorni, inline consumevince su tutti tranne le dimensioni di input più piccole (con non inline consumeleggermente più lento ma ridimensionamento in modo simile). La dequesoluzione basata su & tupling vince solo per gli input più piccoli, a causa di minori costi di installazione e il guadagno è ridotto; si degrada male quando l'iterabile si allunga.

Per la cronaca, la versione adattata della soluzione di Kindall che yields tuples ho usato è stato:

def windowkindalltupled(iterable, n=2, tuple=tuple):
    it = iter(iterable)
    win = deque(islice(it, n), n)
    if len(win) < n:
        return
    append = win.append
    yield tuple(win)
    for e in it:
        append(e)
        yield tuple(win)

Eliminare la memorizzazione nella cache tuplenella riga di definizione della funzione e l'uso di tuplein ciascuna yieldper ottenere la versione più veloce ma meno sicura.


Ovviamente, questo è meno efficiente di quanto potrebbe essere; consumeè uno scopo generale (inclusa la possibilità di fare un completo consume) e quindi necessita di un'importazione extra e di un test per uso n is None. Nel codice reale, se e solo se avessi determinato che le prestazioni erano un problema, o avevo davvero bisogno di un codice più conciso, prenderei in considerazione l'idea di includere il elsecaso consumein window, supponendo che non stavo usando consumeper altro. Ma se le prestazioni non hanno dimostrato di essere un problema, terrei le definizioni separate; la consumefunzione nominata rende l'operazione meno magica / auto-documentante.
ShadowRanger

7

Uso il seguente codice come una semplice finestra scorrevole che utilizza generatori per aumentare drasticamente la leggibilità. La sua velocità è stata finora sufficiente per l'uso nell'analisi della sequenza bioinformatica nella mia esperienza.

Lo includo qui perché non ho ancora visto questo metodo usato. Ancora una volta, non faccio affermazioni sulle sue prestazioni comparate.

def slidingWindow(sequence,winSize,step=1):
"""Returns a generator that will iterate through
the defined chunks of input sequence. Input sequence
must be sliceable."""

    # Verify the inputs
    if not ((type(winSize) == type(0)) and (type(step) == type(0))):
        raise Exception("**ERROR** type(winSize) and type(step) must be int.")
    if step > winSize:
        raise Exception("**ERROR** step must not be larger than winSize.")
    if winSize > len(sequence):
        raise Exception("**ERROR** winSize must not be larger than sequence length.")

    # Pre-compute number of chunks to emit
    numOfChunks = ((len(sequence)-winSize)/step)+1

    # Do the work
    for i in range(0,numOfChunks*step,step):
        yield sequence[i:i+winSize]

3
Lo svantaggio principale qui è la len(sequence)chiamata. Questo non funzionerà se si sequencetratta di un iteratore o generatore. Quando l'input si adatta alla memoria, questo offre una soluzione più leggibile rispetto agli iteratori.
David B.

Sì hai ragione. Questo caso particolare era originariamente pensato per la scansione di sequenze di DNA che di solito sono rappresentate come stringhe. Certamente ha la limitazione di cui parli. Se lo desideri, puoi semplicemente testare ogni sezione per assicurarti che sia ancora della lunghezza giusta e poi dimenticare di dover conoscere la lunghezza dell'intera sequenza. Ma aggiungerebbe un po 'più di sovraccarico (un test len ​​() ogni iterazione).
Gus,

6
def GetShiftingWindows(thelist, size):
    return [ thelist[x:x+size] for x in range( len(thelist) - size + 1 ) ]

>> a = [1, 2, 3, 4, 5]
>> GetShiftingWindows(a, 3)
[ [1, 2, 3], [2, 3, 4], [3, 4, 5] ]

Nel momento in cui vedi "range (len" in Python è un odore di codice.
Mark Lawrence

@MarkLawrence Cosa ti fa pensare che range(lensia un cattivo modello in Python?
duhaime,

5

una versione leggermente modificata della finestra di deque, per renderla una vera finestra scorrevole. In modo che inizi a essere popolato con un solo elemento, quindi raggiunge la dimensione massima della finestra e quindi si restringe man mano che il bordo sinistro si avvicina alla fine:

from collections import deque
def window(seq, n=2):
    it = iter(seq)
    win = deque((next(it, None) for _ in xrange(1)), maxlen=n)
    yield win
    append = win.append
    for e in it:
        append(e)
        yield win
    for _ in xrange(len(win)-1):
        win.popleft()
        yield win

for wnd in window(range(5), n=3):
    print(list(wnd))

questo da

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

3
def rolling_window(list, degree):
    for i in range(len(list)-degree+1):
        yield [list[i+o] for o in range(degree)]

Fatto questo per una funzione media mobile


3

perchè no

def pairwise(iterable):
    "s -> (s0,s1), (s1,s2), (s2, s3), ..."
    a, b = tee(iterable)
    next(b, None)
    return zip(a, b)

È documentato in Python doc . Puoi facilmente estenderlo a una finestra più ampia.


2

Più iteratori!

def window(seq, size, step=1):
    # initialize iterators
    iters = [iter(seq) for i in range(size)]
    # stagger iterators (without yielding)
    [next(iters[i]) for j in range(size) for i in range(-1, -j-1, -1)]
    while(True):
        yield [next(i) for i in iters]
        # next line does nothing for step = 1 (skips iterations for step > 1)
        [next(i) for i in iters for j in range(step-1)]

next(it)aumenta StopIterationquando la sequenza è terminata, e per qualche motivo interessante che è oltre me, l'istruzione yield qui la esclude e la funzione ritorna, ignorando i valori rimanenti che non formano una finestra intera.

Ad ogni modo, questa è la soluzione per le linee minime, ma il cui unico requisito è seqimplementare __iter__o __getitem__e non fare affidamento su itertoolsocollections oltre alla soluzione di @ dansalmo :)


nota: il passo sfalsato è O (n ^ 2) dove n è la dimensione della finestra e si verifica solo alla prima chiamata. Potrebbe essere ottimizzato fino a O (n), ma renderebbe il codice un po 'più complicato: P
jameh

2

Rendiamolo pigro!

from itertools import islice, tee

def window(iterable, size): 
    iterators = tee(iterable, size) 
    iterators = [islice(iterator, i, None) for i, iterator in enumerate(iterators)]  
    yield from zip(*iterators)

list(window(range(5), 3))
# [(0, 1, 2), (1, 2, 3), (2, 3, 4)]

1
#Importing the numpy library
import numpy as np
arr = np.arange(6) #Sequence
window_size = 3
np.lib.stride_tricks.as_strided(arr, shape= (len(arr) - window_size +1, window_size), 
strides = arr.strides*2)

"""Example output:

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

"""


3
Scrivi un testo sulla tua risposta.
jrswgtr,

1

Ho testato alcune soluzioni e una mi è venuta in mente e ho trovato quella che mi è venuta per essere la più veloce, quindi ho pensato di condividerla.

import itertools
import sys

def windowed(l, stride):
    return zip(*[itertools.islice(l, i, sys.maxsize) for i in range(stride)])

1
Sembra simile alla prima soluzione di questa risposta: stackoverflow.com/a/11249883/7851470
Georgy

@georgy Penso di aver saltato quella risposta perché è stata scritta in Python2 ma sono d'accordo, è essenzialmente lo stesso!
Ryan Codrai,

0
>>> n, m = 6, 3
>>> k = n - m+1
>>> print ('{}\n'*(k)).format(*[range(i, i+m) for i in xrange(k)])
[0, 1, 2]
[1, 2, 3]
[2, 3, 4]
[3, 4, 5]

0

Che ne dici di usare il seguente:

mylist = [1, 2, 3, 4, 5, 6, 7]

def sliding_window(l, window_size=2):
    if window_size > len(l):
        raise ValueError("Window size must be smaller or equal to the number of elements in the list.")

    t = []
    for i in xrange(0, window_size):
        t.append(l[i:])

    return zip(*t)

print sliding_window(mylist, 3)

Produzione:

[(1, 2, 3), (2, 3, 4), (3, 4, 5), (4, 5, 6), (5, 6, 7)]

@ keocra cosa significa zip (* t)? Dove posso trovare della documentazione su quel tipo di affermazione?
Shejo284,

1
Python 2.7: docs.python.org/2/library/functions.html#zip , la stella decomprime l'elenco e fornisce i singoli elementi come input per comprimere ( argomenti di decompressione )
keocra,

0

Questa è una vecchia domanda, ma per coloro che sono ancora interessati c'è una grande implementazione di un dispositivo di scorrimento per finestre che utilizza i generatori in questa pagina (di Adrian Rosebrock).

È un'implementazione per OpenCV, tuttavia è possibile utilizzarlo facilmente per qualsiasi altro scopo. Per quelli desiderosi incollerò qui il codice ma per capirlo meglio consiglio di visitare la pagina originale.

def sliding_window(image, stepSize, windowSize):
    # slide a window across the image
    for y in xrange(0, image.shape[0], stepSize):
        for x in xrange(0, image.shape[1], stepSize):
            # yield the current window
            yield (x, y, image[y:y + windowSize[1], x:x + windowSize[0]])

Suggerimento: è possibile controllare la .shapefinestra quando si itera il generatore per scartare quelli che non soddisfano i requisiti

Saluti


0

Modificata la risposta di DiPaolo per consentire riempimento arbitrario e dimensioni del gradino variabili

import itertools
def window(seq, n=2,step=1,fill=None,keep=0):
    "Returns a sliding window (of width n) over data from the iterable"
    "   s -> (s0,s1,...s[n-1]), (s1,s2,...,sn), ...                   "
    it = iter(seq)
    result = tuple(itertools.islice(it, n))    
    if len(result) == n:
        yield result
    while True:        
#         for elem in it:        
        elem = tuple( next(it, fill) for _ in range(step))
        result = result[step:] + elem        
        if elem[-1] is fill:
            if keep:
                yield result
            break
        yield result

0

ecco una fodera. L'ho cronometrato ed è acquistabile per le prestazioni della risposta più alta e migliora progressivamente con sequenze maggiori dal 20% più lente con len (seq) = 20 e 7% più lente con len (seq) = 10000

zip(*[seq[i:(len(seq) - n - 1 + i)] for i in range(n)])

Aggiungi un testo esplicativo con la tua risposta. Non tutti inciampare in questo thread è un Ninja Python.
Abhijit Sarkar il

che è spento da 2, funziona: zip (* [seq [i: (len (seq) - n + 1 + i)] per i nel range (n)])
Gösta Forsum

0

Provare la mia parte, semplice, una fodera, in modo pitonico usando islice. Ma potrebbe non essere ottimale in modo ottimale.

from itertools import islice
array = range(0, 10)
window_size = 4
map(lambda i: list(islice(array, i, i + window_size)), range(0, len(array) - window_size + 1))
# output = [[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6], [4, 5, 6, 7], [5, 6, 7, 8], [6, 7, 8, 9]]

Spiegazione: Creare una finestra usando islice di window_size e iterare questa operazione usando la mappa su tutto l'array.


0

Funzione ottimizzata per lo scorrimento dei dati della finestra in Deep learning

def SlidingWindow(X, window_length, stride):
    indexer = np.arange(window_length)[None, :] + stride*np.arange(int(len(X)/stride)-window_length+4)[:, None]
    return X.take(indexer)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.