滚动还是滑动窗口迭代器?

2024-11-21 08:33:00
admin
原创
7
摘要:问题描述:我需要一个可遍历序列/迭代器/生成器的滚动窗口(又称滑动窗口)。(默认 Python 迭代可以视为一种特殊情况,其中窗口长度为 1。)我目前正在使用以下代码。我怎样才能更优雅和/或更高效地做到这一点?def rolling_window(seq, window_size): it = ite...

问题描述:

我需要一个可遍历序列/迭代器/生成器的滚动窗口(又称滑动窗口)。(默认 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]
"""

对于特定情况window_size == 2(即,迭代序列中相邻、重叠的对),另请参阅如何迭代列表中重叠(当前、下一个)值对?。


解决方案 1:

旧版本的 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我认为文档中的说法更简洁一些,而且效果更好。


如果您的迭代器是一个简单的列表/元组,那么使用指定的窗口大小滑动它的简单方法是:

seq = [0, 1, 2, 3, 4, 5]
window_size = 3

for i in range(len(seq) - window_size + 1):
    print(seq[i: i + window_size])

输出:

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

解决方案 2:

这似乎是为 量身定制的,collections.deque因为您本质上有一个 FIFO(添加到一端,从另一端移除)。但是,即使您使用 ,list您也不应该进行两次切片;相反,您可能应该只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)的项目更快。)我在循环主体中放置了 ;这发挥了双端队列的优势(从一个项目迭代到下一个项目很快,因此此循环比下一个最快的方法 pillmuncher 快 20%)。当我将其更改为在十个窗口中单独查找和添加项目时,情况发生了变化,该tee方法快了 20%。我能够通过在加法中的最后五个项中使用负索引来恢复一些速度,但tee仍然快一点。总的来说,我估计这两种方法对于大多数用途来说都足够快,如果您需要更高的性能,请分析并选择效果最好的方法。

解决方案 3:

我喜欢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]

解决方案 4:

有一个库可以满足您的需要:

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

解决方案 5:

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,请参阅在 python 中高效处理大型 .txt 文件。

解决方案 6:

只是一个快速的贡献。

由于当前 python 文档中的 itertool 示例中没有“window”(即,在http://docs.python.org/library/itertools.html的底部),因此这里有一个基于 grouper 代码的片段,它是给出的示例之一:

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

基本上,我们创建一系列切片迭代器,每个迭代器的起点都向前一个位置。然后,我们将它们压缩在一起。请注意,此函数返回一个生成器(它本身并不是一个生成器)。

与上面的附加元素和前进迭代器版本非常相似,性能(即哪个最好)随列表大小和窗口大小而变化。我喜欢这个,因为它是两行代码(也可以是一行代码,但我更喜欢命名概念)。

事实证明,上述代码是错误的。如果传递给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)

另外,书中还有另一个版本。此版本不是复制迭代器然后多次前进复制,而是在我们将起始位置向前移动时对每个迭代器进行成对复制。因此,迭代器 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)

解决方案 7:

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

解决方案 8:

为了展示如何组合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为迭代器上逐渐增加的消耗n - 1。使用consume而不是将每个迭代器包装在 中islice会稍微快一些(对于足够大的迭代器),因为您只需islice在 阶段支付包装开销consume,而不是在提取每个窗口值的过程中支付(因此它受 的限制n,而不是 中的项目数iterable)。

性能方面,与其他一些解决方案相比,这个解决方案相当不错(而且比我测试过的任何其他解决方案都好,因为它具有可扩展性)。在 Python 3.5.0、Linux x86-64 上使用ipython %timeitmagic 进行了测试。

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到函数定义中以将使用tupleB移动LEGBL

>>> %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基于 & 元组的解决方案仅在最小输入时胜出,因为设置成本较小,而且收益很小;随着可迭代对象变长,其性能会严重下降。

yield需要说明的是,我使用的kindall 解决方案的改编版本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`

解决方案 9:

我使用以下代码作为一个简单的滑动窗口,使用生成器来大幅提高可读性。根据我的经验,它的速度到目前为止足以用于生物信息学序列分析。

我之所以将它包含在这里,是因为我还没有看到过这种方法的使用。同样,我对它的性能不作任何评价。

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]

解决方案 10:

对双端队列窗口进行稍微修改,使其成为真正的滚动窗口。这样它一开始只填充一个元素,然后增长到最大窗口大小,然后在左边缘接近末尾时缩小:

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]

解决方案 11:

为什么不呢

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

它记录在 Python文档中。您可以轻松地将其扩展到更宽的窗口。

解决方案 12:

让我们变得懒惰吧!

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

解决方案 13:

在 Python 3.10 中,我们有一个itertools.pairwise(iterable)可以滑动两个元素的窗口的函数:

这是文档:

返回从输入可迭代对象中获取的连续重叠对。

输出迭代器中的 2 元组数量将比输入数量少一个。如果输入迭代器的值少于两个,则它将为空。

大致相当于:

def pairwise(iterable):
    # pairwise('ABCDEFG') --> AB BC CD DE EF FG
    a, b = tee(iterable)
    next(b, None)
    return zip(a, b)

解决方案 14:

def rolling_window(list, degree):
    for i in range(len(list)-degree+1):
        yield [list[i+o] for o in range(degree)]

为滚动平均函数而制作的

解决方案 15:

我测试了几个解决方案以及我想出的解决方案。我发现我想出的方案是最快的,所以我想分享我的 python3 实现。

import itertools
import sys

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

解决方案 16:

多个迭代器!

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__并且不依赖于itertoolscollections除了@dansalmo 的解决方案:)

解决方案 17:

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

“””

解决方案 18:

toolz / cytoolz包有一个sliding_window函数。

>>> from cytoolz import sliding_window
>>> list(sliding_window(3, range(6))) # returns [(0, 1, 2), (1, 2, 3), (2, 3, 4), (3, 4, 5)]

解决方案 19:

>>> n, m = 6, 3
>>> k = n - m+1
>>> print ('{}
'*(k)).format(*[range(i, i+m) for i in xrange(k)])
[0, 1, 2]
[1, 2, 3]
[2, 3, 4]
[3, 4, 5]

解决方案 20:

如何使用以下内容:

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

解决方案 21:

这是一个老问题,但对于那些仍然感兴趣的人来说,这个页面中使用生成器实现了一个很棒的窗口滑块(由 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在迭代生成器时检查窗口的,以丢弃那些不符合你要求的

干杯

解决方案 22:

修改了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

解决方案 23:

尝试我的部分,使用 islice 的简单、一行、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 创建窗口,并使用 map 在整个数组上迭代此操作。

解决方案 24:

深度学习中滑动窗口数据的优化函数

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)

应用于多维数组

import numpy as np
def SlidingWindow(X, window_length, stride1):
    stride=  X.shape[1]*stride1
    window_length = window_length*X.shape[1]
    indexer = np.arange(window_length)[None, :] + stride1*np.arange(int(len(X)/stride1)-window_length-1)[:, None]
    return X.take(indexer)

解决方案 25:

我的两个版本的window实现

from typing import Sized, Iterable

def window(seq: Sized, n: int, strid: int = 1, drop_last: bool = False):
    for i in range(0, len(seq), strid):
        res = seq[i:i + n]
        if drop_last and len(res) < n:
            break
        yield res


def window2(seq: Iterable, n: int, strid: int = 1, drop_last: bool = False):
    it = iter(seq)
    result = []
    step = 0
    for i, ele in enumerate(it):
        result.append(ele)
        result = result[-n:]
        if len(result) == n:
            if step % strid == 0:
                yield result
            step += 1
    if not drop_last:
        yield result

解决方案 26:

从列表生成固定长度窗口的另一种简单方法

from collections import deque

def window(ls,window_size=3):
    window = deque(maxlen=window_size)

    for element in ls:
        
        if len(window)==window_size:
            yield list(window)
        window.append(element)

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

for w in window(ls):
    print(w)

解决方案 27:

我最终使用的解决方案(保持简单):

def sliding_window(items, size):
    return [items[start:end] for start, end
            in zip(range(0, len(items) - size + 1), range(size, len(items) + 1))]

不用说,该items序列需要可切片。使用索引并不理想,但考虑到替代方案,这似乎是最不坏的选择……这也可以轻松更改为生成器:只需替换[...](...)

解决方案 28:

更新

正如凯利发现的那样,这是一个重复的答案。但我将其留在这里作为反例,因为我添加了一个毫无意义的min

因此,如果您想使用 min 来避免IndexError不要这样做,则没有必要,range将为您处理这种情况。


旧答案

n > len(l)奇怪的是,返回时会自动处理以下内容[],这在语义上是正确的。

>>> l = [0, 1, 2, 3, 4]

>>> n = 2
>>> [l[i: i + min(n, len(l)-i)] for i in range(len(l)-n+1)]
>>> [[0, 1], [1, 2], [2, 3], [3, 4]]
>>>
>>> n = 3
>>> [l[i: i + min(n, len(l)-i)] for i in range(len(l)-n+1)]
>>> [[0, 1, 2], [1, 2, 3], [2, 3, 4]]
>>>
>>> n = 4
>>> [l[i: i + min(n, len(l)-i)] for i in range(len(l)-n+1)]
>>> [[0, 1, 2, 3], [1, 2, 3, 4]]
>>>
>>> n = 5
>>> [l[i: i + min(n, len(l)-i)] for i in range(len(l)-n+1)]
>>> [[0, 1, 2, 3, 4]]
>>>
>>> n = 10 # n > len(l)
>>> [l[i: i + min(n, len(l)-i)] for i in range(len(l)-n+1)]
>>> []

解决方案 29:

我发现这个解决方案比使用内置函数更优雅。

words = ["this", "is", "an", "example"]

def get_sliding_windows(doc, sliding_window, padded=False):
    all_windows = []
    for i in range(sliding_window):
        front = sliding_window-i
        all_windows.append(front*['']+doc+i*[''])
    if padded:
        return np.array(all_windows).transpose()[1:]
    else:
        return np.array(all_windows).transpose()[sliding_window:-1]

>>> get_sliding_windows(words,3)
>>> array([['this', 'is', 'an'],
       ['is', 'an', 'example'],
       ['an', 'example', '']], dtype='<U7')

>>> get_padded_sliding_windows(words,3, True)
>>> array([['', '', 'this'],
       ['', 'this', 'is'],
       ['this', 'is', 'an'],
       ['is', 'an', 'example'],
       ['an', 'example', ''],
       ['example', '', '']], dtype='<U7')

解决方案 30:

这是一行代码。我计算了时间,它的表现与最佳答案相当,并且随着 seq 的增大而逐渐变好,len(seq) = 20 时慢了 20%,len(seq) = 10000 时慢了 7%

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

这相当于:

win_list = []
for win_start_idx in range(n):
    win_end_idx = (len(seq) - n + 1 + i)
    win_list.append(seq[win_start_idx:win_end_idx])
win_list = zip(*win_list)  # transpose rows of columns to columns of rows
相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   601  
  华为IPD与传统研发模式的8大差异在快速变化的商业环境中,产品研发模式的选择直接决定了企业的市场响应速度和竞争力。华为作为全球领先的通信技术解决方案供应商,其成功在很大程度上得益于对产品研发模式的持续创新。华为引入并深度定制的集成产品开发(IPD)体系,相较于传统的研发模式,展现出了显著的差异和优势。本文将详细探讨华为...
IPD流程是谁发明的   7  
  如何通过IPD流程缩短产品上市时间?在快速变化的市场环境中,产品上市时间成为企业竞争力的关键因素之一。集成产品开发(IPD, Integrated Product Development)作为一种先进的产品研发管理方法,通过其结构化的流程设计和跨部门协作机制,显著缩短了产品上市时间,提高了市场响应速度。本文将深入探讨如...
华为IPD流程   9  
  在项目管理领域,IPD(Integrated Product Development,集成产品开发)流程图是连接创意、设计与市场成功的桥梁。它不仅是一个视觉工具,更是一种战略思维方式的体现,帮助团队高效协同,确保产品按时、按质、按量推向市场。尽管IPD流程图可能初看之下显得错综复杂,但只需掌握几个关键点,你便能轻松驾驭...
IPD开发流程管理   8  
  在项目管理领域,集成产品开发(IPD)流程被视为提升产品上市速度、增强团队协作与创新能力的重要工具。然而,尽管IPD流程拥有诸多优势,其实施过程中仍可能遭遇多种挑战,导致项目失败。本文旨在深入探讨八个常见的IPD流程失败原因,并提出相应的解决方法,以帮助项目管理者规避风险,确保项目成功。缺乏明确的项目目标与战略对齐IP...
IPD流程图   8  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用