代码之家  ›  专栏  ›  技术社区  ›  Peterhack

条件元素与(numpy)

  •  0
  • Peterhack  · 技术社区  · 6 年前

    如果前面的数字是负数,我找到了一个求和的方法:

    def func(x):
        for i, value in enumerate(x):
            if i == len(x)-1:
                break
            if value < 0:
                x[i+1] += value
        x = x.clip(min=0)
        return x
    
    data = np.array([-3, 4, -2, -2, 6])
    print(func(data))
    >>>> [0 1 0 0 2]
    

    有矢量化的numpy解决方案吗?这是一个非常小的数据样本,但它将变得相当大,并且是2D,例如:

    data = np.array([[-3, 4, -2, -2, 6],[1, -2, -3, 7, 1]])
    

    我想把它用在划船上。

    2 回复  |  直到 6 年前
        1
  •  0
  •   Nils Werner    6 年前

    广义地说,矢量化依赖于数组的许多元素可以独立于所有其他元素进行处理的事实,然后可以利用可以应用到数组的所有元素的操作。但是,由于计算依赖于以前迭代的结果,因此需要在数据中线性运行。

    因此,可能无法将问题完全矢量化。但是由于每个行的计算独立于其他行,所以向量化还有一些空间:这里是一个解决方案,它可以遍历所有列并在所有行上循环。

    def func(x):
        x = x.copy()
        for i in range(len(x) - 1):
            mask = x[i, ...] < 0
            x[i+1, mask, ...] += x[i, mask, ...]
    
        x = x.clip(min=0)
        return x
    
    data = np.array([[-3, 4, -2, -2, 6],[1, -2, -3, 7, 1]])
    func(data.T)
    # array([[0, 1],
    #        [1, 0],
    #        [0, 0],
    #        [0, 2],
    #        [2, 1]])
    

    我意识到,不是想单独处理每一行,而是选择将这两个替换为一般的迭代,这样在数组的第一维上迭代比迭代最后一个维度更有效:

    data = numpy.random.randint(0, 10, size=(10000, 10000))
    %timeit colwise_func(data)  # 1.08 s ± 35.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
    %timeit rowwise_func(data)  # 2.31 s ± 65.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
    
        2
  •  0
  •   Mario García    5 年前

    可以使用数据的二进制数组。一旦定义了阈值,就将其二值化。 np.where :

    data = np.array([-3, 4, -2, -2, 6])
    binarized = np.where(data>0, 1, 0)
    # array([0, 1, 0, 0, 1])
    

    这个 在哪里 函数返回一个大小相同的数组 data ,其中高于阈值的任何值(此处等于0)都将设置为1,而所有其他值都将设置为0。

    然后简单地把它的累积和乘以它自己。它将对所有值求和,并在没有有效和的地方设置零。

    np.cumsum(binarized)*binarized
    # array([0, 1, 0, 0, 2])
    

    对于二维数组,使用类似的方法,但是给出要求和的轴。在您的情况下,您希望它沿行排列,因此将其设置为 axis=1 :

    data = np.array([[-3, 4, -2, -2, 6],[1, -2, -3, 7, 1]])
    binarized = np.where(data>0, 1, 0)
    np.cumsum(binarized, axis=1)*binarized
    # array([[0, 1, 0, 0, 2],
    #        [1, 0, 0, 2, 3]])
    

    你的职能只能是:

    def func(data, t=0, ax=1):
        b = np.where(data>t, 1, 0)
        return np.cumsum(b, axis=ax)*b
    

    有参数 t 设置阈值,同时设置参数 ax 是轴的总和。给予一个 None 将对数组的所有值求和。