【问题标题】:Summing up non-zero elements in numpy array总结numpy数组中的非零元素
【发布时间】:2020-09-29 17:56:06
【问题描述】:

我想对数组 (1-d) 的非零元素求和,但对正整数和负整数(它们只能是 1 和 2)分别进行求和,并且在它们所在的位置显示零。

数组示例:

array = np.array([0, 0, 0, -1, -1, 0, 1, 2, 1, 1, 0, -1, 0, 1, 1, -1, -2])

输出:

array([0, 0, 0, -2, 0, 5, 0, -1, 0, 2, -3])

我认为我的问题是我不知道如何将数组中的正负值序列分开。

【问题讨论】:

  • 你能在纸上做这个吗?如果是这样,你能写出如何做的步骤吗?如果是这样,您知道如何将其转换为代码吗?你坚持这个过程的哪一部分?或者你有没有尝试过什么?
  • 你会打开其他包,比如 Pandas 吗?
  • @RandomDavis 我喜欢这个评论 :-)。实际上,我是在纸上做的,就像我做其他我遇到问题的事情一样,但显然我不够聪明。

标签: python numpy numpy-ndarray


【解决方案1】:

这是一种方法-

def sum_by_signs(a):
    m1 = a<0
    m2 = a>0
    m0 = a==0 # or ~m1 & ~m2
    p = np.flatnonzero(m0[:-1] | np.diff(m1) | np.diff(m2))+1
    return np.add.reduceat(a, np.r_[0,p])

或者将 np.r_[0 部分带入布尔构造部分 -

def sum_by_signs_v2(a):
    m1 = a<0
    m2 = a>0
    m0 = a==0 # or ~m1 & ~m2
    p = np.flatnonzero(np.r_[True, m0[:-1] | np.diff(m1) | np.diff(m2)])
    return np.add.reduceat(a, p)

说明

我们开始考虑根据符号变化或遇到一系列 0 时将数组拆分为“孤岛”,在这种情况下,我们希望将每个元素拆分为一个单独的元素。通过拆分,将其视为列表列表,如果这样更容易理解。现在,游戏是我们如何获得这些分裂。我们需要表示这些岛屿的开始、停止索引的索引。如前所述,共有三种情况,符号从+ 变为- 或反之亦然或0 序列。

因此,布尔掩码的结构用于为这些索引提供一次性切片,以检测从+- 的符号变化,反之亦然,结合np.diff(m1) | np.diff(m2)m0[:-1] 的最后一个是0s 的序列。然后将这些索引馈送到np.add.reduceat 以获得间隔总和。

示例运行 -

In [208]: a
Out[208]: array([ 0,  0,  0, -1, -1,  0,  1,  2,  1,  1,  0, -1,  0,  1,  1, -1, -2])

In [209]: sum_by_signs(a)
Out[209]: array([ 0,  0,  0, -2,  0,  5,  0, -1,  0,  2, -3])

In [211]: a
Out[211]: array([ 1,  2,  0, -1, -1,  0,  1,  2,  1,  1,  0, -1,  0,  1,  1, -1, -2])

In [212]: sum_by_signs(a)
Out[212]: array([ 3,  0, -2,  0,  5,  0, -1,  0,  2, -3])

In [214]: a
Out[214]: 
array([ 1,  2,  0, -1, -1,  0,  1,  2,  1,  1,  0, -1,  0,  1,  1, -1, -2,
        0])

In [215]: sum_by_signs(a)
Out[215]: array([ 3,  0, -2,  0,  5,  0, -1,  0,  2, -3,  0])

【讨论】:

  • 你能向初学者解释一下为什么以及如何工作吗?这显然是一个可行的解决方案,但对于除了 numpy 专家之外的任何人来说似乎都非常不透明。
  • @RandomDavis 看看添加的解释是否有意义。
  • @Divakar 这很好用,而且在大型阵列上也很快。非常感谢您的帮助。
【解决方案2】:

这解决了问题,但肯定有更聪明的方法来做到这一点

array = [0, 0, 0, -1, -1, 0, 1, 2, 1, 1, 0, -1, 0, 1, 1, -1, -2]

switch = 0
while switch == 0:
    for i in range(len(array)):
        try:
            array[i+1]
            if array[i] > 0 and array[i+1] > 0: 
                array[i] += array[i + 1]
                array.pop(i + 1)
                break
            elif array[i] < 0 and array[i+1] < 0:   
                array[i] += array[i + 1]
                array.pop(i + 1)
                break
        except:
            switch = 1
            break

数组最后的值为[0, 0, 0, -2, 0, 5, 0, -1, 0, 2, -3]

【讨论】:

  • 谢谢。我做了类似的事情,但对性能和复杂性不满意。不过感谢您的帮助。
猜你喜欢
  • 1970-01-01
  • 2018-01-27
  • 2019-06-28
  • 2019-02-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-23
  • 2018-12-03
相关资源
最近更新 更多