在 Python 中滑动 window

Sliding window in Python

我在标记化文本文档中滑动 window 使用了以下著名代码:

def window(fseq, window_size):
    "Sliding window"
    it = iter(fseq)
    result = tuple(islice(it, 0, window_size, round(window_size/4)))
    if len(result) == window_size:
        yield result
    for elem in it:
        result = result[1:] + (elem,)
        result_list = list(result)
        yield result_list

当我想用 window 大小小于 6 调用我的函数时,一切正常,但是当我增加它时,文本的开头被剪切了。

例如:

c=['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']
print(list(window(c, 4)))
print(list(window(c, 8)))

输出:

[('A', 'B', 'C', 'D'), ['B', 'C', 'D', 'E'], ['C', 'D', 'E', 'F'], ['D', 'E', 'F', 'G'], ['E', 'F', 'G', 'H'], ['F', 'G', 'H', 'I'],...

[['C', 'E', 'G', 'I'], ['E', 'G', 'I', 'J'], ['G', 'I', 'J', 'K'], ['I', 'J', 'K', 'L'], ['J', 'K', 'L', 'M']...

怎么了?为什么在第一个输出中第一个元素在圆括号中?

我对 print(list(window(c, 8))) 的预期输出是:

[['A','B','C', 'D', 'E', 'F','G','H'], ['C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'], ['E', 'F', 'G', 'H', 'I', 'K', 'L', 'M']...

您的版本不正确。它向 islice() 函数添加了第四个参数(步长),以限制第一个切片的大小:

result = tuple(islice(it, 0, window_size, round(window_size/4)))

对于 45round(window_size/4) 产生 1,默认步长。但是对于较大的值,这会产生一个步长,以保证从第一个 window 中省略值,因此下一个测试 len(result) == window_size 保证为假。

删除步长参数,您将再次获得第一个 window。另见 Rolling or sliding window iterator in Python.

第一个结果在 'round brackets' 中,因为它是一个元组。如果您想要一个列表,请在您的代码中使用 list() 而不是 tuple()

如果您想让 window 以大于 1 的步长滑动,则不应更改初始 window。您需要在迭代时从 window 添加和删除 step 大小的元素。使用 while 循环更容易完成:

def window_with_larger_step(fseq, window_size):
    """Sliding window

    The step size the window moves over increases with the size of the window.
    """
    it = iter(fseq)
    result = list(islice(it, 0, window_size))
    if len(result) == window_size:
        yield result
    step_size = max(1, int(round(window_size / 4)))  # no smaller than 1
    while True:
        new_elements = list(islice(it, step_size))
        if len(new_elements) < step_size:
            break
        result = result[step_size:] + list(islice(it, step_size))
        yield result

这会将 step_size 个元素添加到 运行 结果中,从开头删除 step_size 个元素以保持 window 大小均匀。

演示:

>>> print(list(window_with_larger_step(c, 6)))
[['A', 'B', 'C', 'D', 'E', 'F'], ['C', 'D', 'E', 'F', 'I', 'J'], ['E', 'F', 'I', 'J', 'M', 'N'], ['I', 'J', 'M', 'N', 'Q', 'R'], ['M', 'N', 'Q', 'R', 'U', 'V'], ['Q', 'R', 'U', 'V', 'Y', 'Z']]
>>> print(list(window_with_larger_step(c, 8)))
[['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'], ['C', 'D', 'E', 'F', 'G', 'H', 'K', 'L'], ['E', 'F', 'G', 'H', 'K', 'L', 'O', 'P'], ['G', 'H', 'K', 'L', 'O', 'P', 'S', 'T'], ['K', 'L', 'O', 'P', 'S', 'T', 'W', 'X'], ['O', 'P', 'S', 'T', 'W', 'X']]
>>> print(list(window_with_larger_step(c, 10)))
[['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'], ['D', 'E', 'F', 'G', 'H', 'I', 'J', 'N', 'O', 'P'], ['G', 'H', 'I', 'J', 'N', 'O', 'P', 'T', 'U', 'V'], ['J', 'N', 'O', 'P', 'T', 'U', 'V', 'Z']]