【问题标题】:replacing a list of numbers with a list of their multiplications用它们的乘法列表替换数字列表
【发布时间】:2021-04-24 01:20:26
【问题描述】:

我有一个数字列表arr 和一个窗口大小n。 我想有效地(可能使用 numpy)计算一个新列表,其中列表中的每个新元素都是窗口中所有元素的乘积。 例如,如果arr = [1, 2, 3, 4, 5]n = 3 我希望它返回res = [6, 24, 60] 而对于n = 2 我希望[2, 6, 12, 20]

【问题讨论】:

  • 很有趣,像一种减窗器?
  • 是这样的

标签: python list performance numpy multiplication


【解决方案1】:

使用 SciPy 的 generic_filter 并传入 NumPy 的 prod 作为应用于每个切片的函数:

In [86]: import numpy as np
    ...: from scipy.ndimage import generic_filter as gf

In [87]: def reducer(arr, n):
    ...:     start = n//2
    ...:     stop = len(arr) - (n - 1)//2
    ...:     result = gf(arr, np.prod, n, mode='constant', cval=0)
    ...:     return result[start:stop]

In [88]: arr = np.array([1, 2, 3, 4, 5])

In [89]: reducer(arr, 2)
Out[89]: array([ 2,  6, 12, 20])

In [90]: reducer(arr, 3)
Out[90]: array([ 6, 24, 60])

In [91]: reducer(arr, 4)
Out[91]: array([ 24, 120])

【讨论】:

    【解决方案2】:

    如果您想要一个非 numpy 解决方案,您可以使用切片通过循环来执行此操作:

    from operator import mul
    from functools import reduce
    
    def slicer(lst, n):
        i = 0
        while True:
            _slice = lst[i:i+n]
            if not len(_slice) == n:
                break
            yield reduce(mul, _slice)
            i += 1
    
    >>> list(slicer(arr, 3))
    [6, 24, 60]
    >>> list(slicer(arr, 2))
    [2, 6, 12, 20]
    

    或者,使用for 循环:

    def slicer(lst, n):
        for i in range(len(lst) - n + 1):
            _slice = lst[i:i+n]
            yield reduce(mul, _slice)
    
    
    >>> list(slicer(arr, 3))
    [6, 24, 60]
    >>> list(slicer(arr, 2))
    [2, 6, 12, 20]
    

    【讨论】:

    • 我希望它尽可能简单易懂。我认为它可以用一个 numpy oneliner 来完成,如果可能的话我想要那个解决方案
    • @GalSuchetzky 对多行提出要求并不总是可取的。 Enrico 的 pandas 解决方案可以用一行来表达,但分解后更好看
    【解决方案3】:

    我的解决方案涉及 Pandas。

    import pandas as pd
    import numpy as np
    
    
    arr = pd.Series([1, 2, 3, 4, 5])
    window_size = 3
    rolling = arr.rolling(window_size)
    result = rolling.apply(np.prod)
    
    

    生成的数组与原始数组的长度相同,第一个元素设置为 NaN。 您可以使用result.dropna(inplace=True) 轻松删除它们。 我希望你可以使用 Pandas,它们的滚动窗口功能非常好!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-11-30
      • 1970-01-01
      • 2016-01-20
      • 2019-06-04
      • 1970-01-01
      • 1970-01-01
      • 2020-05-30
      • 1970-01-01
      相关资源
      最近更新 更多