Итератор скользящего или скользящего окна? - PullRequest
131 голосов
/ 26 июля 2011

Мне нужно скользящее окно (или скользящее окно), повторяемое по последовательности / итератору / генератору. По умолчанию итерацию Python можно рассматривать как особый случай, когда длина окна равна 1. В настоящее время я использую следующий код. У кого-нибудь есть более Pythonic, менее многословный или более эффективный метод для этого?

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

Ответы [ 19 ]

2 голосов
/ 27 декабря 2014

почему бы и нет

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

Это задокументировано в Python doc .Вы можете легко расширить его до более широкого окна.

2 голосов
/ 21 октября 2013

Несколько итераторов!

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) повышает StopIteration, когда последовательность завершена, и по какой-то крутой причине, которая мне не подходит, оператор yield здесь исключает ее, и функция возвращает значение, игнорируя оставшиеся значения, которые не образуют полное окно.

В любом случае, это решение с наименьшим количеством строк, единственное требование которого заключается в том, чтобы seq реализовывал либо __iter__, либо __getitem__ и не полагался на itertools или collections, кроме решения @ dansalmo:)

2 голосов
/ 30 сентября 2014
def rolling_window(list, degree):
    for i in range(len(list)-degree+1):
        yield [list[i+o] for o in range(degree)]

Сделано для функции скользящего среднего

1 голос
/ 09 января 2019

Давайте сделаем это ленивым!

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 голос
/ 02 августа 2018
#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]

"" "

0 голосов
/ 19 июня 2018

Изменено Ответ DiPaolo , чтобы разрешить произвольное заполнение и переменный размер шага

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 голосов
/ 24 июля 2013
>>> 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 голосов
/ 24 марта 2017

Это старый вопрос, но для тех, кто все еще интересуется, есть отличная реализация ползунка окна, использующего генераторы на этой странице (от Адриана Роузброка).

Это реализация для OpenCV, однако вы можете легко использовать ее для любых других целей.Для желающих я вставлю сюда код, но для лучшего понимания рекомендую посетить исходную страницу.

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

Совет: Вы можете проверить .shape окна при итерации генератора, чтобы отменить те, которые не соответствуют вашим требованиям

Приветствия

0 голосов
/ 06 апреля 2016

Как насчет использования следующего:

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)

Вывод:

[(1, 2, 3), (2, 3, 4), (3, 4, 5), (4, 5, 6), (5, 6, 7)]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...