ローリングまたはスライディングウィンドウイテレータ?


150

シーケンス/イテレータ/ジェネレータで反復可能なローリングウィンドウ(別名スライディングウィンドウ)が必要です。デフォルトの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]
"""

3
反復するときに(たとえばsum()またはmax())、各ウィンドウでなんらかの操作を実行する 場合は、(ウィンドウサイズに関係なく)各ウィンドウの新しい値を一定の時間で計算する効率的なアルゴリズムがあることに注意してください。これらのアルゴリズムのいくつかをPythonライブラリーにまとめました:ローリング
Alex Riley

回答:


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 2011

19
@TakenMacGuy:私はそのレシピの推論の作者が何であるか知りませんが、私は2も選択します。2は、最小の有用なウィンドウサイズです(そうでない場合、反復するだけでウィンドウは必要ありません)。また、それも一般的です前の(または次の)項目を知る必要があります。他の特定のnよりも間違いなくそうです。
キンドール

27
この例がドキュメントから削除された理由を誰かが知っていますか?何か問題がありましたか、それとももっと簡単な代替案がありますか?
2013


2
いつfor elem in itループに入りますか?
Glassjawed

47

これcollections.dequeは、基本的にFIFOを持っている(一方の端に追加し、もう一方の端から削除する)ため、あつらえのようです。ただし、aを使用しても、list2回スライスすることはできません。代わりに、おそらくpop(0)リストとappend()新しいアイテムだけからとるべきです。

オリジナルを模した、最適化された両端キューベースの実装を次に示します。

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

私のテストでは、ほとんどの場合、ここに投稿された他のすべてのものを簡単に打ち負かしていますが、Pillmuncherのteeバージョンは、大きなイテラブルと小さなウィンドウの場合はこれに勝っています。大きなウィンドウでは、deque実際の速度で再び先に進みます。

の個々のアイテムへのアクセスdequeは、リストまたはタプルを使用する場合よりも高速または低速です。(最初の方が速いアイテム、または負のインデックスを使用する場合は最後の方が速いアイテムです。)sum(w)ループの本体にaを入れました。これはdequeの強みを発揮します(1つの項目から次の項目への反復は高速であるため、このループは、次に高速な方法であるピルマンチャーよりも20%高速で実行されました)。10個のウィンドウで個別に検索して項目を追加するように変更すると、テーブルが変わり、teeメソッドが20%高速になりました。さらに、最後の5項に負のインデックスを使用することで、ある程度の速度を回復できましたteeが、それでも少し高速でした。全体として、どちらかがほとんどの用途で十分高速であると推定します。もう少しパフォーマンスが必要な場合は、プロファイルを作成し、最適に動作するものを選択します。


11
yield win同じオブジェクトへの参照のイテレータを返さないようにするyield tuple(win)yield list(win)、それを防ぐ必要がありdequeます。
Joel Cornett 2013年

1
これをPyPIに送信しました。でインストールしpip install sliding_window、で実行しfrom sliding_window import windowます。
Thomas Levine

1
あなたが考える場合は、ショックのためにいるlist(window(range(10)))ようなものを生成する必要があり、[[0,1]、[1,2]、[2,3]、...]
ポール・

1
それは明らかにしません。のような何かをするlist(list(x) for x in window(range(10)))か、それをイテレータに追加する必要があります。一部のアプリケーションではこれが重要で、他のアプリケーションでは重要ではありません。速度を重視していたため、私は選択せず、必要に応じてウィンドウをコピーする責任を呼び出し元に課しました。
キンダル2016

1
必要なtuple()前の利回りを追加する場合、この方法は他の方法に勝る利点はありません。
kawing-chiu 2017

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テストから、これはDaniel DePaoloの速度よりもはるかに遅く(約2:1の比率で)、あまり「いい」とは感じません。
David B.

@David B .:私のボックスでは、Daniel DePaoloよりも約8%遅いだけです。
ピルムンチャー

@pillmuncher:Python 2.7または3.x?2.7を使っていました。この比率は、の値にもかなり影響されますsize。これを増やすと(たとえば、イテラブルが100000要素の長さの場合、ウィンドウサイズを1000にすると)、増加する場合があります。
デビッドB.

2
@David B .:あなたが言うことは理にかなっています。私のコードでは、のセットアップ時間itersはO(size!)であり、next()(でizip())何度も呼び出すのは、タプルを2回コピーするよりもはるかに時間がかかります。私はPython 2.6.5を使用していました。
ピルムンチャー

@pillmuncher:つまり、セットアップ時間itersはO(size ^ 2)ですよね?
David B.

20

ここでのサポートを追加する一般化だstepfillvalueパラメータは:

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パラメータの使用例については、Pythonでの大きな.txtファイルの効率的な処理をご覧ください。


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実際にはOPの要求に合致するために除去する必要がありますlist(more_itertools.windowed(range(6), 3))
user3780389

10

すぐに貢献してください。

現在のpythonのドキュメントには、itertoolの例(つまり、http: //docs.python.org/library/itertools.htmlの下部)に「ウィンドウ」がないため、グルーパーのコードに基づくスニペットを次に示します。与えられた例の1つです。

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

基本的に、一連のスライスされたイテレータを作成します。それぞれに開始点が1つ先にあります。次に、これらを一緒に圧縮します。この関数はジェネレーターを返します(これは直接ジェネレーター自体ではありません)。

上記のappending-elementとadvancing-iteratorのバージョンと同様に、パフォーマンス(つまり、最高)はリストのサイズとウィンドウのサイズによって異なります。これは2ライナーであるため、私はこれが好きです(1ライナーの場合もありますが、命名の概念を好みます)。

上記のコードは間違っていることがわかります。iterableに渡されるパラメーターがシーケンスの場合は機能しますが、イテレーターの場合は機能しません。イテレータである場合、同じイテレータがislice呼び出し間で共有されます(ただしtee'dではありません)。

ここにいくつかの固定コードがあります:

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)

また、本のもう1つのバージョン。イテレーターをコピーしてからコピーを何度も進める代わりに、このバージョンでは、開始位置を前方に移動するときに各イテレーターのペアごとのコピーを作成します。したがって、イテレーター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支払うだけなので、(十分に大きいイテラブルの場合)わずかに高速になります(したがって、)。isliceconsumeniterable

パフォーマンスに関しては、他のいくつかのソリューションと比較して、これはかなり優れています(そして、私がテストした他のどのソリューションよりも優れています)。ipython %timeitマジックを使用して、Python 3.5.0、Linux x86-64でテストされています。

Kindall氏だdequeソリューション使用してパフォーマンス/正しさのために微調整し、islice代わりに自宅圧延ジェネレータ式のと反復可能なウィンドウよりも短い場合、それは結果が得られていないので、結果の長さをテストするだけでなく、合格maxlendeque位置の代わりに、キーワードによる(入力が小さい場合は驚くほど違います):

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

以前の適応されたkindallソリューションと同じですが、それぞれyield winyield tuple(win)ジェネレーターからの結果の保存が機能するように変更されているため、保存されたすべての結果は実際に最新の結果のビューではなく(他のすべての合理的なソリューションはこのシナリオでは安全です)、tuple=tuple関数定義に追加されます使用を移動するtupleからBLEGBL

>>> %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ケース、特にセットアップのオーバーヘッドが作業の重要な部分である小さな入力の場合:consumen 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 tupleの私が使用されました:

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イテレータまたはジェネレータの場合、これは機能しません。入力がメモリに収まる場合、イテレータよりも読みやすいソリューションが提供されます。
デビッドB.

はい、あなたが正しい。この特定のケースは、もともと文字列として表されるDNAシーケンスをスキャンするためのものでした。それは確かにあなたが言及する制限があります。必要に応じて、各スライスをテストして、適切な長さであることを確認し、シーケンス全体の長さを知る必要がないようにします。しかし、それは少し多くのオーバーヘッドを追加します(len()テストごとに繰り返し)。
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] ]

Pythonで「range(len)」が表示された瞬間は、コードの匂いです
Mark Lawrence

@MarkLawrence range(lenPythonの悪いパターンは何だと思いますか?
duhaime

5

それを真のローリングウィンドウにするために、dequeウィンドウのわずかに変更されたバージョン。そのため、要素が1つだけ入力され始め、最大ウィンドウサイズまで拡大し、左端が端に近づくにつれて縮小します。

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 docに記載されています。広いウィンドウに簡単に拡張できます。


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ウィンドウ全体を形成していない残りの値を無視してシーケンスが終了し、私を超えますいくつかのクールな理由のために、yield文ここexceptsでそれをし、関数が戻ります。

とにかく、これは最少ラインのソリューションですが、@ dansalmoのソリューションに依存するか、またはそれ以外にseq実装するか、__iter__または__getitem__それに依存することが唯一の要件です:)itertoolscollections


注:ずらすステップはO(n ^ 2)で、nはウィンドウのサイズで、最初の呼び出しでのみ発生します。O(n)まで最適化できますが、コードが少し面倒になります:P
jameh 2013年

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

私はいくつかのソリューションをテストし、思いついた1つのソリューションを試したところ、思いついた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
Georgy

@georgy Python2で記述されているため、その回答はスキップしたと思いますが、基本的には同じです。
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

以下を使用するのはどうですか:

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 2017

1
Python 2.7:docs.python.org/2/library/functions.html#zip、スターはリストを解凍し、個々の要素をzipへの入力として提供します(引数の解凍
keocra

0

これは古い質問ですが、まだ興味がある人のために、このページのジェネレータを使用したウィンドウスライダの優れた実装があります(Adrian Rosebrockによる)。

これは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

こちらはワンライナーです。時間を計ったところ、トップアンサーのパフォーマンスに匹敵し、len(seq)= 20の場合は20%遅く、len(seq)= 10000の場合は7%遅くなります。

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

答えを説明テキストに追加してください。このスレッドに出くわすすべてがPython Ninjaであるとは限りません。
Abhijit Sarkar

これは2オフです。これは機能します:zip(* [seq [i:(len(seq)-n + 1 + i)] for i in range(n)])
GöstaForsum

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

説明:window_sizeのisliceを使用してウィンドウを作成し、すべての配列に対してmapを使用してこの操作を繰り返します。


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)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.