【问题标题】:Summing three consecutive number when equal to or great than 0 - Python当等于或大于 0 时对三个连续数字求和 - Python
【发布时间】:2021-03-15 19:31:40
【问题描述】:

我在 Python 中使用 numpy

我有一个数字数组,例如:

arr = np.array([0.1, 1, 1.2, 0.5, -0.3, -0.2, 0.1, 0.5, 1)

如果i 是数组中的一个位置,我想创建一个函数,它创建i 和前两个数字的运行总和,但仅在等于或大于 0 时累加该数字。

也就是说,数组中的负数在计算三数运行和时都等于0。

例如,我要在这里寻找的答案是

2.3, 2.7, 1.7, 0.5, 0.1, 0.6, 1.6

新数组比原数组少了两个元素,因为前两个数的计算无法完成。

谢谢!

【问题讨论】:

    标签: python arrays function numpy


    【解决方案1】:

    正如 Dani Mesejo 所回答的,您可以使用跨步技巧。您可以使用剪辑或布尔索引来处理

    1. arr[arr<0]=0 将所有低于 0 的元素设置为 0
    2. as_strided 接收数组、视图的预期形状(7,3) 和各个轴上的步幅数(8,8)。这是您必须分别在axis0axis1 中移动才能访问下一个元素的字节数。例如。如果要移动每 2 个元素,则可以将其设置为 (16,8)。这意味着您每次将移动 16 个字节以获取axis0 中的元素(即0.1->1.2->0->0.1->..,直到形状为7),每次移动8 个字节以获取axis1 中的元素(即0.1->1->1.2,直到形状3)

    谨慎使用此功能!始终使用 x.strides 来定义 strides 参数以避免损坏内存!

    1. 最后,将此数组视图与axis=1 相加得到滚动总和。
    arr = np.array([0.1, 1, 1.2, 0.5, -0.3, -0.2, 0.1, 0.5, 1])
    w = 3  #rolling window
    
    arr[arr<0]=0
    
    shape = arr.shape[0]-w+1, w  #Expected shape of view (7,3)
    strides = arr.strides[0], arr.strides[0] #Strides (8,8) bytes
    rolling = np.lib.stride_tricks.as_strided(arr, shape=shape, strides=strides)
    
    rolling_sum = np.sum(rolling, axis=1)
    rolling_sum
    
    array([2.3, 2.7, 1.7, 0.5, 0.1, 0.6, 1.6])
    

    【讨论】:

    • as_strided 的解释很好 :)
    • 上面的代码是否适用于立方体?我有一个时间维度,保留它会很有用
    • 你的意思是更高维的张量?是的。只要您了解as_strided 的工作原理,您就可以简单地获取arr.strides,它是一个4 维数组的4 元素元组并运行上面的代码。您必须定义预期的输出形状以及沿输出形状的这些轴需要采取的步幅。
    【解决方案2】:

    你可以cliprollsum

    import numpy as np
    
    
    def rolling_window(a, window):
        """Recipe from https://stackoverflow.com/q/6811183/4001592"""
        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 = np.array([0.1, 1, 1.2, 0.5, -0.3, -0.2, 0.1, 0.5, 1])
    
    res = rolling_window(np.clip(a, 0, a.max()), 3).sum(axis=1)
    print(res)
    

    输出

    [2.3 2.7 1.7 0.5 0.1 0.6 1.6]
    

    【讨论】:

      【解决方案3】:

      您可以使用np.correlatearr 的剪辑上扫描3 个ones 的数组以获得所需的输出

      In [20]: np.correlate(arr.clip(0), np.ones(3), mode='valid')
      Out[20]: array([2.3, 2.7, 1.7, 0.5, 0.1, 0.6, 1.6])
      

      【讨论】:

        【解决方案4】:
        arr = np.array([0.1, 1, 1.2, 0.5, -0.3, -0.2, 0.1, 0.5, 1])
        
        def sum_3(x):
            collector = []
            
            for i in range(len(arr)-2):            
                collector.append(sum(arr[i:i+3][arr[i:i+3]>0]))
            return collector
        
        #output
        
        [2.3, 2.7, 1.7, 0.5, 0.1, 0.6, 1.6]
        
        

        最简单易懂的方法。如果三个连续数字的索引为True,则收集器将追加它们的总和,否则,它们都将转向0s。

        方法不通用,连续3次,但你可以适应它。

        def sum_any(x,n):
            collector = []
            for i in range(len(arr)-(n-1)):            
                collector.append(sum(arr[i:i+n][arr[i:i+n]>0]))
            return collector
        

        【讨论】:

          【解决方案5】:

          掩码数组和 view_as_windows(在后台使用 numpy strides)就是为此目的而构建的:

          from skimage.util import view_as_windows
          arr = view_as_windows(arr, 3)
          arr2 = np.ma.masked_array(arr, arr<0).sum(-1)
          

          输出:

          [2.3 2.7 1.7 0.5 0.1 0.6 1.6]
          

          【讨论】:

            猜你喜欢
            • 2021-07-13
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-12-18
            • 2012-11-08
            • 2021-01-28
            • 2021-08-31
            相关资源
            最近更新 更多