【问题标题】:Python sliding windows of a list列表的Python滑动窗口
【发布时间】:2021-06-14 12:21:13
【问题描述】:

是否有一种高效或优雅的方式来检索 Python 中列表的所有 k 大小子列表?例如:

arr = [2, 3, 5, 7, 11, 13]

我想要所有 3 元素子列表:

result = [[2, 3, 5],
          [3, 5, 7],
          [5, 7, 11],
          [7, 11, 13]]

我知道我可以使用 for 循环创建它,使用 arr[i:i+3] 对列表进行切片,但我正在处理的列表非常庞大,我希望有一个有效的机制,或者至少是一个优雅或 Pythonic 的机制.

我也在使用 Pandas,很高兴使用 Pandas 机制。

【问题讨论】:

标签: python python-3.x pandas list dataframe


【解决方案1】:

如果您真的想构建列表,我认为您不会比这样的基本列表理解做得更好:

arr = [2, 3, 5, 7, 11, 13]
result = [arr[i:i+k] for i in range(len(arr)-k+1)]

如果你想尽量减少内存使用,你可以使用生成器:

arr = [2, 3, 5, 7, 11, 13]
def window(arr, k):
    for i in range(len(arr)-k+1):
        yield arr[i:i+k]

for group in window(arr, 3):
    ...  # do something with group

您还可以在zip 一起k 列表的副本中执行某些操作,每个副本偏移一个。但这将占用与第一个解决方案一样多的内存,可能没有太大的性能优势。

在 numpy 或 pandas 中可能有一些快速有效的东西,但您需要更多地展示您的输入和输出应该是什么样子。

还有一些其他想法 here,但它们专注于一般的可迭代对象(您只能将项目拉出一次),而不是列表(您可以通过索引访问项目,可能重复)。

【讨论】:

  • 如果你不需要发电机,这里有一个单行:slidingwindows = lambda L, n: [L[i:i+n] for i in range(len(L)-n+1)]
【解决方案2】:

如果您的来源(列表)很大,则意味着来源提供者应该按需产生价值。这样做的方法是制作一个生成器。

来自文件的假设源生成器;

def gen_value():
    with open('big-file.txt') as f:
        for line in f:
            for x in line.split():
                yield int(x)

grouper 函数 recipe 可用于消耗生成器:

def grouper(iterable, n, fillvalue=None):
    "Collect data into fixed-length chunks or blocks"
    # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx"
    args = [iter(iterable)] * n
    return zip_longest(*args, fillvalue=fillvalue)

所以你可以拨打list(grouper(gen(), 3))

【讨论】:

    【解决方案3】:

    您可以使用more_itertools

    import more_itertools
    list(more_itertools.windowed(arr,3))
    

    [(2, 3, 5), (3, 5, 7), (5, 7, 11), (7, 11, 13)]
    

    使用itertools:

    from itertools import islice
    
    def pairwise(iterable, n):
        "s -> (s0,s1,..s(n-1)), (s1,s2,.., sn), (s2, s3,..,s(n+1)), ..."
        iters = iter(iterable)
        result = tuple(islice(iters, n))
        if len(result) == n:
            yield result
        for elem in iters:
            result = result[1:] + (elem,)
            yield result
    

    【讨论】:

      【解决方案4】:

      你可以使用strides:

      arr = [2, 3, 5, 7, 11, 13]
      
      def rolling_window(a, window):
          shape = a.shape[:-1] + (a.shape[-1] - window + 1, window)
          strides = a.strides + (a.strides[-1],)
          return np.lib.stride_tricks.as_strided(a, shape=shape, strides=strides)
      
      a = rolling_window(np.array(arr), 3)
      print (a)
      [[ 2  3  5]
       [ 3  5  7]
       [ 5  7 11]
       [ 7 11 13]]
      
      
      print (a.tolist())
      [[2, 3, 5], 
       [3, 5, 7], 
       [5, 7, 11], 
       [7, 11, 13]]
      

      【讨论】:

        猜你喜欢
        • 2016-03-06
        • 1970-01-01
        • 1970-01-01
        • 2013-04-05
        • 1970-01-01
        • 1970-01-01
        • 2012-10-12
        • 2012-05-16
        • 2017-01-16
        相关资源
        最近更新 更多