Ітератор вікон, що котяться чи ковзають?


151

Мені потрібно вікно прокатки (він же розсувне вікно), яке можна передати на послідовність / ітератор / генератор. Ітерація Python за замовчуванням може вважатися особливим випадком, де довжина вікна дорівнює 1. Зараз я використовую наступний код. Хтось має більш пітонічний, менш багатослівний або більш ефективний метод для цього?

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
Якщо ви хочете виконати якусь операцію над кожним вікном під час ітерації (наприклад, sum()або max()), варто пам’ятати, що існують ефективні алгоритми для обчислення нового значення для кожного вікна за постійний час (незалежно від розміру вікна). Я зібрав кілька таких алгоритмів разом у бібліотеці Python: прокат .
Алекс Райлі

Відповіді:


123

У старій версії документів Python є один із itertoolsприкладами :

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

Той, який є в документах, трохи більш лаконічний і використовує itertoolsдля більшого ефекту, який я собі уявляю.


2
Приємна відповідь, але (а я знаю, що ви просто відтворюєте рецепт як пов'язаний), мені цікаво, чому розмір вікна за замовчуванням повинен бути 2? Чи повинен він взагалі мати дефолт?
SingleNegationElimination

19
@TakenMacGuy: Я не знаю, що автор міркувань цього рецепту, але я також обрав би 2. 2 - це найменший корисний розмір вікна (інакше ви просто ітератуєте і не потрібно вікно), і це також звичайне необхідно знати попередній (або наступний) пункт, мабуть, більше, ніж будь-який інший п.
kindall

27
Хтось знає, чому цей приклад був видалений з документів? Чи щось із цим не було, або зараз є простіша альтернатива?
Вім

12

2
Коли б хтось увійшов до for elem in itциклу?
Glassjawed

47

Це здається індивідуально, collections.dequeоскільки у вас є FIFO (додайте до одного кінця, видаліть з іншого). Однак навіть якщо ви використовуєте a, listви не повинні нарізати двічі; натомість вам, мабуть, слід просто pop(0)зі списку та append()нового пункту.

Ось оптимізована реалізація на основі deque з малюнком після оригіналу:

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

У моїх тестах вона зручно перемагає все інше, розміщене тут, більшість часу, хоча teeверсія таблетки перемагає її для великих ітерабелів і маленьких вікон. На великих вікнах dequeзнову тягнеться вперед із силою швидкістю.

Доступ до окремих предметів dequeможе бути швидшим або повільнішим, ніж зі списками або кортежами. (Елементи, що знаходяться на початку, швидше, або елементи в кінці, якщо ви використовуєте від'ємний індекс.) Я поміщаю sum(w)в тіло своєї петлі; це грає на силу дека (ітерація від одного предмета до іншого швидка, тому ця петля пробіглася на 20% швидше, ніж наступний найшвидший метод, пігулки). Коли я змінив його на індивідуальний пошук і додав елементи у вікно з десяти, таблиці повернулися, і teeметод став на 20% швидшим. Мені вдалося відновити деяку швидкість, використовуючи додаткові індекси за останні п’ять доданків, але teeвсе-таки трохи швидше. В цілому, я вважаю, що будь-який з них досить швидкий для більшості застосувань, і якщо вам потрібно трохи більше продуктивності, профіліруйте та виберіть той, який найкраще працює.


11
yield winповинен бути yield tuple(win)або yield list(win)не допускати повернення ітератора посилань на один і той же dequeоб'єкт.
Джоел Корнетт

1
Я подав це в PyPI . Встановіть pip install sliding_windowі запустіть із from sliding_window import window.
Томас Левін

1
Вас чекає шок, якщо ви думаєте, що ви list(window(range(10)))повинні створити щось на зразок [[0,1], [1,2], [2,3], ...]
Пол

1
Це, очевидно, не буде; вам потрібно буде зробити щось на кшталт list(list(x) for x in window(range(10)))або ще додати це до ітератора. Для деяких додатків це буде мати значення, для інших це не так, а оскільки я рухався за швидкістю, я не вибрав і поклав на абонента, що вимагає скопіювати вікно, якщо потрібно.
kindall

1
Якщо додати необхідні tuple()до врожаю, цей спосіб не має жодної переваги перед іншими.
кавінг-чиу

35

Мені подобається 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)

дає:

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

З моїх швидких timeitтестів, це набагато повільніше, ніж у Деніела Депаоло (приблизно у співвідношенні 2: 1) і не відчуває себе набагато "приємніше".
Девід Б.

@David B.: У моєму ящику це лише на 8% повільніше, ніж у Даніеля Депаоло.
пігулка

@pillmuncher: Python 2.7 або 3.x? Я використовував 2.7. Коефіцієнт також досить чутливий до значення size. Якщо ви збільшите його (наприклад, якщо тривалість ітерабету становить 100000 елементів, зробіть розмір вікна 1000), можливо, ви побачите збільшення.
Девід Б.

2
@David B.: Те, що ви говорите, має сенс. У моєму коді час налаштування для itersO (розмір!), А виклик next()багато разів (in izip()), ймовірно, забирає набагато більше часу, ніж копіювання каналу двічі. Я використовував Python 2.6.5, BTW.
пігулка

@pillmuncher: Ви маєте на увазі, час налаштування для itersO (розмір ^ 2), правда?
Девід Б.

20

Ось узагальнення , яке додає підтримку step, fillvalueпараметри:

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

Це дає в шматки sizeелементи за раз прокатних stepпозицій за ітерацією, набиваючи кожен шматок, fillvalueякщо це необхідно. Приклад для 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 * *]

Для прикладу випадку використання stepпараметра див . Ефективна обробка великого .txt-файлу в python .


17

Є бібліотека, яка робить саме те, що потрібно:

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=3насправді потрібно видалити, щоб відповідати запиту ОП:list(more_itertools.windowed(range(6), 3))
user3780389

10

Просто швидкий внесок.

Оскільки в поточних документах python немає "вікна" в прикладах itertool (тобто внизу http://docs.python.org/library/itertools.html ), ось фрагмент на основі коду для збирача, який є одним із наведених прикладів:

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

В основному ми створюємо серію нарізаних ітераторів, кожен з яких має відправну точку на одну точку далі. Потім ми їх застібаємо разом. Зауважте, ця функція повертає генератор (це безпосередньо не сам генератор).

Так само, як і версії додаючого елемента та версії прогресуючого ітератора, продуктивність (тобто, що найкраще) змінюється залежно від розміру списку та розміру вікна. Мені це подобається, тому що це дволінійний (це може бути однолінійний, але я вважаю за краще називати поняття).

Виявляється, наведений вище код невірний . Він працює, якщо параметр, переданий ітерабельному, є послідовністю, але не, якщо це ітератор. Якщо це ітератор, той самий ітератор поділяється (але не tee'd) між викликами islice, і це погано розбиває речі.

Ось декілька фіксованих кодів:

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)

Також ще одна версія для книг. Замість того, щоб копіювати ітератор, а потім просунути копії багато разів, ця версія робить парні копії кожного ітератора під час переміщення вихідної позиції вперед. Таким чином, ітератор t забезпечує як "повний" ітератор вихідну точку при t, а також основу для створення ітератора 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

Просто щоб показати, як можна поєднувати itertoolsрецепти , я поширюю pairwiseрецепт якомога прямо назад до windowрецепту, використовуючи consumeрецепт:

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)

windowРецепт такий же , як для pairwise, він просто заміняє один елемент «спожити» на другому tee-ED ітератора з прогресивно зростаючої споживає на n - 1ітератори. Використання consumeзамість того, щоб загортати кожен ітератор, isliceє незначно швидшим (за досить великі ітерабелі), оскільки ви платите isliceзагортання накладних витрат лише під час consumeфази, а не під час вилучення кожного значення вікна-редактора (тому воно обмежене n, а не кількістю елементів у iterable).

В порівнянні з деякими іншими рішеннями, ефективні, це досить добре (і краще, ніж будь-яке інше рішення, яке я перевірив, коли воно масштабується). Тестовано на Python 3.5.0, Linux x86-64, використовуючи ipython %timeitмагію.

Kindall це на dequeрішення , оптимальне для продуктивності / коректності, використовуючи isliceзамість виразу генератора домашнього прокату і тестування отриманої довжини , так що не дають результати , коли ітеріруемое коротше , ніж вікно, а також проходженням maxlenз dequeпозиційно замість за ключовим словом (робить дивовижну різницю для менших входів):

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

Те саме, що і попереднє адаптоване подібне рішення, але з кожним yield winзміненим yield tuple(win)таким чином зберігання результатів з генератора працює без усіх збережених результатів, що насправді є переглядом останнього результату (всі інші розумні рішення безпечні в цьому сценарії) та додавання tuple=tupleдо визначення функції для переміщення використання tupleз Bв LEGBна 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

consumeрозчин на основі, показаний вище:

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

Так само consume, як , але вкладений elseвипадок, consumeщоб уникнути виклику функції та n is Noneтесту для скорочення часу виконання, особливо для невеликих входів, де накладні витрати є важливою частиною роботи:

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

(Побічна примітка. Варіант, pairwiseщо використовує teeаргумент за замовчуванням 2 teeрази для створення вкладених об'єктів, тому будь-який заданий ітератор просувається лише один раз, не самостійно споживається все більше разів, подібно до відповіді MrDrFenner подібний до не вкладеного consumeі повільніше, ніж накреслені consumeу всіх тестах, тому я опустив це результати для стислості).

Як бачите, якщо вам не байдуже можливість абонента, який потребує збереження результатів, моя оптимізована версія рішення kindall виграє більшість часу, за винятком "великого ітерабельного, невеликого розміру вікна" (де вказується consumeвиграш ); вона швидко деградує, оскільки ітерабельний розмір збільшується, при цьому зовсім не деградує, оскільки розмір вікна збільшується (кожне інше рішення деградує повільніше, оскільки ітерабельний розмір збільшується, але також зменшується для збільшення розміру вікна). Він навіть може бути адаптований до корпусу "необхідних кортежів" шляхом загортання map(tuple, ...), яке працює дещо повільніше, ніж увімкнення функціонування, але це тривіально (займає 1-5% довше) і дозволяє вам тримати гнучкість роботи швидше коли ви можете терпіти повторне повернення одного і того ж значення.

Якщо вам потрібна безпека від збереження повернень, вбудовані consumeвиграші на всіх, крім найменших розмірів вводу (при цьому неінліноване consumeтрохи повільніше, але масштабування аналогічно). Рішення dequeна основі & tupling виграє лише за найменші входи через менші витрати на налаштування, а коефіцієнт підсилення невеликий; вона погано деградує, оскільки тривалість ітерабельності стає довшою.

Для запису, адаптованої версії рішення Kindall, що yieldS tupleS я використовував:

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)

Залиште кешування tupleв рядку визначення функції та використання tupleв кожному, yieldщоб отримати швидшу, але менш безпечну версію.


Очевидно, що це менш ефективно, ніж могло б бути; consumeє загальним призначенням (включаючи можливість зробити повне consume) і тому потребує додаткового імпорту та тесту на використання для n is None. У реальному коді, тоді і тільки тоді , коли я б вирішив продуктивність була проблема, або я дійсно потребував в більш короткий код, я б розглянути вбудовування в elseразі consumeв window, за умови , що я не використав consumeнічого іншого. Але якщо ефективність не виявилася б проблемою, я б дотримувався окремих визначень; названа consumeфункція робить операцію менш магічною / самодокументуванням.
ShadowRanger

7

Я використовую наступний код як просте розсувне вікно, яке використовує генератори для різкого підвищення читабельності. Наразі його швидкість була достатньою для використання в аналізі послідовностей біоінформатики в моєму досвіді.

Я включаю його сюди, оскільки я ще не бачив цього методу. Знову ж таки, я не претендую на його порівняну ефективність.

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
Основний недолік тут - len(sequence)дзвінок. Це не працюватиме, якщо sequenceє ітератором чи генератором. Коли вхід вписується в пам'ять, це пропонує більш читабельне рішення, ніж ітератори.
Девід Б.

Так, ви праві. Цей конкретний випадок спочатку був призначений для сканування послідовностей ДНК, які зазвичай представлені у вигляді рядків. Це, звичайно, має обмеження, яке ви згадуєте. Якщо ви хотіли, ви можете просто протестувати кожен фрагмент, щоб переконатися, що його довжина все-таки правильна, а потім забути про необхідність знати довжину всієї послідовності. Але це додало б трохи більше накладних (тестування len () кожної ітерації).
Гас

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

Щойно ви побачите "range (len" "в Python - це кодовий запах.
Mark Lawrence

@MarkLawrence Що ви вважаєте range(len, що це поганий зразок python?
duhaime

5

трохи модифікована версія вікна deque, щоб зробити його справжнім вікном, що котиться. Так що він починає заповнюватися лише одним елементом, потім зростає до максимального розміру вікна, а потім скорочується, коли його лівий край підходить до кінця:

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

це дає

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

Зробили це для ковзної середньої функції


3

чому ні

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

Документально в Python док . Ви можете легко поширити його на ширше вікно.


2

Кілька ітераторів!

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

У будь-якому випадку, це рішення, що має найменші рядки, але єдиною вимогою є те, що seqвпроваджувати __iter__або __getitem__не покладатися на рішення, itertoolsа collectionsтакож на додаток @ dansalmo :)


зауважте: крок ухилення - це O (n ^ 2), де n - розмір вікна, і відбувається лише під час першого дзвінка. Це може бути оптимізовано до O (n), але це зробить код трохи месиєром: P
jameh

2

Давайте зробимо це лінивим!

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
Будь ласка, напишіть текст про свою відповідь.
jrswgtr

1

Я випробував кілька рішень, і одне, що я придумав, і знайшов те, що я придумав, щоб бути найшвидшим, тому я подумав, що поділюсь ним.

import itertools
import sys

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

1
Схоже на перше рішення з цієї відповіді: stackoverflow.com/a/11249883/7851470
Георгій

@georgy Я думаю, що я пропустив цю відповідь, тому що вона була написана в Python2, але я згоден, це по суті те саме!
Райан Кодрай

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

Як щодо використання наступного:

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

@ keocra що означає zip (* t)? Де я можу знайти документацію щодо такого виписки?
Shejo284

1
Python 2.7: docs.python.org/2/library/functions.html#zip , зірка розпаковує список та надає окремі елементи як вхід до zip ( розпакування аргументів )
keocra

0

Це старе питання, але для тих, хто все ще цікавить, є чудова реалізація віконного повзунка з використанням генераторів на цій сторінці (Адріан Розборок).

Це реалізація для 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

Модифікована відповідь 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

ось один лайнер. Я приурочив її, і це порівняно з продуктивністю верхньої відповіді і стає прогресивно краще з більшим seq від 20% повільніше з len (seq) = 20 і 7% повільніше з len (seq) = 10000

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

Будь ласка, додайте пояснювальний текст зі своєю відповіддю. Не всі натрапляють на цю нитку - ніндзя Python.
Абхіджіт Саркар

що вимкнено на 2, це працює: zip (* [seq [i: (len (seq) - n + 1 + i)] для i в діапазоні (n)])
Gösta Forsum

0

Спробую мою частину, простий, один лайнер, пітонічний спосіб, використовуючи islice. Але, можливо, не буде оптимально ефективним.

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

Пояснення: Створіть вікно за допомогою islice of window_size та повторіть цю операцію за допомогою карти по всьому масиву.


0

Оптимізована функція для ковзання даних вікон у глибокому навчанні

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)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.