रोलिंग या खिड़की खिसकाने वाला?


151

मुझे एक सीक्वेंस / इट्रेटर / जनरेटर पर चलने वाली खिड़की (उर्फ स्लाइडिंग विंडो) की जरूरत है। डिफ़ॉल्ट पायथन पुनरावृत्ति को एक विशेष मामला माना जा सकता है, जहां खिड़की की लंबाई 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()) यह ध्यान में असर लायक कुशल एल्गोरिदम में प्रत्येक विंडो के लिए नए मूल्य की गणना करने देखते हैं कि है निरंतर समय (भले ही विंडो आकार का)। मैंने पायथन लाइब्रेरी में इनमें से कुछ एल्गोरिदम को एक साथ एकत्रित किया है: रोलिंग
एलेक्स रिले

जवाबों:


123

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 क्यों होना चाहिए? क्या इसमें बिल्कुल चूक होनी चाहिए?
22

19
@TakenMacGuy: मुझे पता नहीं है कि उस रेसिपी के तर्क के लेखक क्या हैं, लेकिन मैं भी चुनूंगा 2. 2 सबसे छोटी उपयोगी विंडो का आकार है (अन्यथा आप सिर्फ इसे पुनरावृत्त कर रहे हैं और विंडो की आवश्यकता नहीं है), और यह भी आम है पिछले (या अगले) आइटम को जानने की जरूरत है, यकीनन किसी भी अन्य विशिष्ट एन की तुलना में अधिक है।
किंडल

27
क्या किसी को पता है कि इस उदाहरण को डॉक्स से क्यों हटाया गया? क्या इसमें कुछ गड़बड़ थी, या अब एक आसान विकल्प है?
विम

12
उदाहरण को हटाने के बारे में उत्सुक हो गए और 26 अक्टूबर, 2003 को किए
दूसरा

2
एक for elem in itपाश में कब प्रवेश करेगा ?
ग्लासजॉव

47

ऐसा लगता है कि आपके लिए collections.dequeअनिवार्य रूप से एक FIFO है (एक छोर से जोड़ें, दूसरे से निकालें)। हालाँकि, भले ही आप एक का उपयोग करें 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)))या फिर इसे पुनरावृत्त में जोड़ें। कुछ अनुप्रयोगों के लिए यह बात मायने रखता है, दूसरों के लिए नहीं, और चूंकि मैं गति के लिए जा रहा था इसलिए मैंने निर्वाचित नहीं किया और जरूरत पड़ने पर खिड़की को कॉपी करने के लिए कॉलर पर ओनस डाल दिया।
किंडल

1
यदि आप tuple()उपज से पहले जरूरत को वापस जोड़ते हैं , तो इस विधि का दूसरों पर कोई फायदा नहीं है।
kawing-chiu

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 अनुपात) और अधिक "अच्छे" महसूस नहीं करता है।
डेविड बी।

@ डेविड बी .: मेरे बॉक्स पर डैनियल डेपोलो की तुलना में यह केवल 8% धीमा है।
पिलमंचर

@ पिलमंचर: पायथन 2.7 या 3.x? मैं 2.7 का उपयोग कर रहा था। अनुपात भी मूल्य के प्रति काफी संवेदनशील है size। यदि आप इसे बढ़ाते हैं (उदाहरण के लिए, यदि चलने योग्य 100000 तत्व लंबा है, तो विंडो का आकार 1000 बनाएं), आप वृद्धि देख सकते हैं।
डेविड बी।

2
@ दाविद बी .: आप जो कहते हैं वह समझ में आता है। मेरे कोड में itersO (आकार!) के लिए सेटअप समय है, और next()कई बार (में izip()) कॉल करना संभवत: एक टुपल को दो बार कॉपी करने की तुलना में बहुत अधिक समय लगता है। मैं पायथन 2.6.5, BTW का उपयोग कर रहा था।
स्तंभकार

@ पिलमंचर: आपका मतलब है, सेटअप समय itersओ (आकार ^ 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 फ़ाइल को कुशलतापूर्वक संसाधित करना देखें ।


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

बस एक त्वरित योगदान है।

चूंकि वर्तमान अजगर डॉक्स में इटर्टूल उदाहरणों में "विंडो" नहीं है (यानी, 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)

मूल रूप से, हम कटा हुआ पुनरावृत्तियों की एक श्रृंखला बनाते हैं, जिनमें से प्रत्येक एक प्रारंभिक बिंदु एक स्थान से आगे होता है। फिर, हम इन्हें एक साथ जोड़ते हैं। ध्यान दें, यह फ़ंक्शन एक जनरेटर लौटाता है (यह सीधे स्वयं एक जनरेटर नहीं है)।

ऊपर दिए गए एपेंडिंग-एलिमेंट और एडवांसिंग-इटरेटर संस्करणों की तरह, प्रदर्शन (यानी, जो सबसे अच्छा है) सूची आकार और विंडो आकार के साथ बदलता रहता है। मुझे यह पसंद है क्योंकि यह एक दो-लाइनर है (यह एक-लाइनर हो सकता है, लेकिन मैं नामकरण अवधारणाओं को पसंद करता हूं)।

यह पता चला है कि उपरोक्त कोड गलत है । यह काम करता है यदि पैरामीटर चलने योग्य है योग्य के है एक अनुक्रम है, लेकिन नहीं अगर यह एक है। यदि यह एक इट्रिऐटर है, तो समान इटैलर कॉल के बीच साझा किया जाता है (लेकिन टी नहीं) और यह चीजों को बुरी तरह से तोड़ता है।

यहाँ कुछ निश्चित कोड है:

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 बनाने का आधार भी होता है:

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सीधे नुस्खा में वापस ला रहा हूं :windowconsume

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उत्तरोत्तर पर खपत में वृद्धि के साथ एड इटरेटर n - 1iterators। consumeप्रत्येक isliceपुनरावृत्त को लपेटने के बजाय का उपयोग करना थोड़ा तेज है (पर्याप्त रूप से बड़े पुनरावृत्तियों के लिए) क्योंकि आप केवल चरण के isliceदौरान रैपिंग ओवरहेड का भुगतान करते हैं consume, न कि प्रत्येक विंडो-एड मान को निकालने की प्रक्रिया के दौरान (इसलिए यह बाध्य है n, न कि मदों की संख्या।iterable )।

प्रदर्शन-वार, कुछ अन्य समाधानों की तुलना में, यह बहुत अच्छा है (और किसी अन्य समाधान की तुलना में बेहतर है जिसे मैंने तराजू के रूप में परीक्षण किया है)। ipython %timeitजादू का उपयोग करके पायथन 3.5.0, लिनक्स x86-64 पर परीक्षण किया गया ।

kindall है dequeसमाधान का उपयोग करके, प्रदर्शन / शुद्धता के लिए बदलाव isliceएक घर लुढ़का जनरेटर अभिव्यक्ति के बजाय और जिसके परिणामस्वरूप लंबाई परीक्षण तो यह परिणाम नहीं करता है जब iterable खिड़की से भी कम है, साथ ही गुजर maxlenकी dequepositionally बजाय कीवर्ड द्वारा (छोटे इनपुट के लिए एक आश्चर्यजनक अंतर बनाता है):

>>> %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मामले में , विशेष रूप से छोटे इनपुट के लिए जहां सेटअप ओवरहेड काम का एक सार्थक हिस्सा है: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जो नेस्टेड teeऑब्जेक्ट बनाने के लिए 2 के डिफ़ॉल्ट तर्क के साथ बार-बार उपयोग करता है , इसलिए किसी भी दिए गए इटरेटर को केवल एक बार उन्नत किया जाता है, स्वतंत्र रूप से बढ़ती हुई संख्या का उपभोग नहीं किया जाता है, जैसा कि MrDrFenner का जवाब गैर- इनबिल्ड के समान है। consumeऔर consumeसभी परीक्षणों पर इनबिल्ड की तुलना में धीमा है , इसलिए मैंने इसे संक्षिप्तता के लिए उन परिणामों को छोड़ दिया है)।

जैसा कि आप देख सकते हैं, यदि आपको कॉल करने वाले को परिणाम स्टोर करने की आवश्यकता की संभावना के बारे में परवाह नहीं है , तो किंडल के समाधान का मेरा अनुकूलित संस्करण "बड़े चलने योग्य, छोटे खिड़की के आकार के मामले" को छोड़कर अधिकांश समयconsume जीतता है (जहां इनबिल्ड जीत होती है ); iterable size बढ़ने पर यह जल्दी खराब हो जाता है, जबकि खिड़की का आकार बढ़ने पर बिलकुल भी नीचा नहीं होता (iterable size बढ़ने के लिए हर दूसरा घोल धीरे-धीरे कम होता जाता है, लेकिन खिड़की के आकार में बढ़ोतरी भी घटती है)। इसे "रैपिंग टपल" केस के लिए रैप करके भी अनुकूलित किया जा सकता है map(tuple, ...), जो फंक्शन में ट्यूपलिंग लगाने की तुलना में थोड़ा धीमा चलता है, लेकिन यह तुच्छ है (1-5% अधिक समय लगता है) और आपको तेज चलने की सुविधा देता है जब आप बर्दाश्त कर सकते हैं बार-बार एक ही मूल्य लौटाने।

यदि आपको संग्रहित किए जाने वाले रिटर्न के खिलाफ सुरक्षा की आवश्यकता है, तो consumeसभी पर सबसे छोटे इनपुट आकार (गैर-इनलाइन consumeथोड़ा धीमा लेकिन समान रूप से स्केलिंग के साथ) में जीतता हैdequeऔर tupling आधारित समाधान जीत केवल छोटी से छोटी जानकारी के लिए, छोटे सेटअप लागत की वजह से के लिए, और लाभ छोटा है, जब यह चलने योग्य हो जाता है तो यह बुरी तरह खराब हो जाता है।

रिकॉर्ड, kindall के समाधान के लिए अनुकूलित संस्करण के लिए yieldरों 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फ़ंक्शन ऑपरेशन को कम जादुई / स्व-दस्तावेजीकरण बनाता है।
शैडो रेंजर

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एक इट्रेटर या जनरेटर है। जब इनपुट मेमोरी में फिट होता है, तो यह पुनरावृत्तियों की तुलना में अधिक पठनीय समाधान प्रदान करता है।
डेविड बी।

हाँ तुम सही हो। यह विशेष रूप से मामला मूल रूप से डीएनए अनुक्रमों को स्कैन करने के लिए था, जिसे आमतौर पर स्ट्रिंग्स के रूप में दर्शाया जाता है। यह निश्चित रूप से आपके द्वारा उल्लेखित सीमा है। यदि आप चाहते हैं कि आप प्रत्येक स्लाइस का परीक्षण कर सकें, तो सुनिश्चित करें कि यह अभी भी सही लंबाई है और फिर पूरे अनुक्रम की लंबाई जानने के बारे में भूल जाएं। लेकिन यह थोड़ा अधिक उपरि (एक लेन () हर पुनरावृत्ति का परीक्षण) जोड़ देगा।
गस

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

तत्काल आप पायथन में "रेंज (लेन") देखते हैं यह एक कोड गंध है।
मार्क लॉरेंस

@MarkLawrence आपको क्या लगता range(lenहै कि अजगर में एक बुरा पैटर्न है?
दुहामइ

5

एक सच्ची रोलिंग विंडो बनाने के लिए, डॉक विंडो का थोड़ा संशोधित संस्करण। ताकि यह सिर्फ एक तत्व से आबाद होने लगे, फिर यह अधिकतम खिड़की के आकार तक बढ़ जाता है, और फिर बाएं किनारे पर आते ही सिकुड़ जाता है:

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)

यह पाइथन डॉक में प्रलेखित है । आप इसे आसानी से विस्तृत विंडो में विस्तारित कर सकते हैं।


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__या @ dansalmo के समाधान __getitem__पर itertoolsया collectionsइसके अलावा पर भरोसा न करें :)


नोट: स्टैगर स्टेप O (n ^ 2) है जहाँ n विंडो का आकार है, और केवल पहली कॉल पर होता है। इसे O (n) के लिए अनुकूलित किया जा सकता है, लेकिन यह कोड को थोड़ा
गड़बड़ कर देगा

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

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

@ कीकोरा का मतलब क्या होता है? मुझे उस तरह के बयान पर कुछ दस्तावेज कहां मिल सकते हैं?
Shejo284

1
पायथन 2.7: docs.python.org/2/library/functions.html#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

मनमाने ढंग से भरने और चर चरण आकार की अनुमति देने के लिए संशोधित डायपॉलो का उत्तर

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 से लेन (seq) = 20 और 7% धीमी लेन (seq) = 10000 के साथ बेहतर हो जाता है

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

कृपया अपने उत्तर के साथ कुछ व्याख्यात्मक पाठ जोड़ें। इस धागे के पार ठोकर खाने वाला हर कोई अजगर निंजा नहीं है।
अभिजीत सरकार

वह 2 से बंद है, यह काम करता है: जिप (* [seq [i: (len (seq) - n + 1 + i)] i के लिए i in रेंज (n)])
Gösta Forsum

0

मेरे हिस्से की कोशिश कर रहा है, सरल, एक लाइनर, आइलिस का उपयोग करके pythonic तरीका। लेकिन, हो सकता है कि यह कुशल रूप से कुशल न हो।

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 का उपयोग करके विंडो बनाएं और सभी ऐरे पर मैप का उपयोग करके इस ऑपरेशन को पुनरावृत्त करें।


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 Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.