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
パフォーマンスに関しては、他のいくつかのソリューションと比較して、これはかなり優れています(そして、私がテストした他のどのソリューションよりも優れています)。ipython
%timeit
マジックを使用して、Python 3.5.0、Linux x86-64でテストされています。
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
以前の適応されたkindallソリューションと同じですが、それぞれ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氏のソリューションの適応バージョンyield
S 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
を削除して、より高速ですが安全性の低いバージョンを取得します。
sum()
またはmax()
)、各ウィンドウでなんらかの操作を実行する 場合は、(ウィンドウサイズに関係なく)各ウィンドウの新しい値を一定の時間で計算する効率的なアルゴリズムがあることに注意してください。これらのアルゴリズムのいくつかをPythonライブラリーにまとめました:ローリング。