【问题标题】:Only add value if value is greater zero in Python of multidimensional array仅当多维数组的 Python 中的值大于零时才添加值
【发布时间】:2017-11-25 22:15:12
【问题描述】:

我有一个这样的数组:tmp.shape = (128, 64, 64)

我沿128 轴计算所有零,如下所示:

nonzeros = np.count_nonzero(tmp, axis=0) // shape = (64, 64)

我有一个数组c.shape = (64, 64)

现在我想将 c 的值沿 128 轴添加到 tmp,但前提是 tmp 的值 > 0:

for i in range(tmp.shape[0]):
    axis1 = tmp[i,:,:]
    tmp[i, :, :] += (c / nonzeros) // only if tmp[i, :, :] > 0

这可以在短时间内完成吗?还是我必须使用多个循环? 我希望任何人都可以提出一个没有另一个循环的解决方案

这样的事情不起作用:

tmp[i, tmp > 0.0, tmp > 0.0] += (c / nonzeros)

IndexError: 数组索引过多

长版

for i in range(tmp.shape[0]):
    for x in range(tmp.shape[1]):
        for y in range(tmp.shape[2]):
            pixel = tmp[i, x, y]
            if pixel != 0:
                pixel += (c[x,y] / nonzeros[x,y])

【问题讨论】:

  • 发布的解决方案是否适合您?
  • 是的,对不起,我最近很忙,所以没有马上回答。

标签: python numpy multidimensional-array vectorization


【解决方案1】:

好吧,您基本上是将广播的c/nonzeros 添加到 tmp 数组中,除了 tmp 元素为零的地方。因此,一种方法是预先存储0s 的掩码,添加c/nonzeros,最后使用掩码重置tmp 元素。

因此,实现将是 -

mask = tmp==0
tmp+= c/nonzeros
tmp[mask] = 0

运行时测试

方法-

# @DSM's soln
def fast(tmp, c, nonzeros):
    return tmp + np.where(tmp > 0, c/nonzeros, 0)

# Proposed in this post
def fast2(tmp, c, nonzeros):
    mask = tmp==0
    tmp+= c/nonzeros
    tmp[mask] = 0
    return tmp

时间安排 -

In [341]: # Setup inputs
     ...: M,N = 128,64
     ...: tmp = np.random.randint(0,10,(M,N,N)).astype(float)
     ...: c = np.random.rand(N,N)*100
     ...: nonzeros = np.count_nonzero(tmp, axis=0)
     ...: 
     ...: # Make copies for testing as input would be edited with the approaches
     ...: tmp1 = tmp.copy()
     ...: tmp2 = tmp.copy()
     ...: 

In [342]: %timeit fast(tmp1, c, nonzeros)
100 loops, best of 3: 2.22 ms per loop

In [343]: %timeit fast2(tmp2, c, nonzeros)
1000 loops, best of 3: 1.61 ms per loop

较短的替代方案

如果您正在寻找一个紧凑的代码,这是另一个使用 non-0s 的掩码与 c/nonzeros 进行广播元素乘法并添加到 tmp 并因此有一个单行解决方案,就像这样 -

tmp += (tmp!=0)*(c/nonzeros)

注意:为了避免被0 分割,我们可以在0s 处编辑nonzeros,而不是0,比如1,然后使用发布的方法,像这样-

nonzeros = np.where(nonzeros > 0, nonzeros, 1)

【讨论】:

  • 你说的没错,但我收到了这个:RuntimeWarning: divide by zero encountered in true_divide tmp += np.where(tmp > 0, c / nonzeros, 0)我没有用我的方法收到这个。
  • 您能否将其添加到您的解决方案中:nonzeros = np.where(nonzeros > 0, nonzeros, 1) ?我不想编辑它,因为这是你的答案,我不想功劳。
  • @thigi 谢谢!已编辑。
【解决方案2】:

您可以使用np.where 和广播。修复示例代码后(添加到像素不会修改 tmp),

def fast(tmp, c, nonzeros):
    return tmp + np.where(tmp > 0, c/nonzeros, 0)

给我

In [6]: tmp = np.random.randint(0, 5, (128, 64, 64)).astype(float)
   ...: c = np.random.randint(10, 15, (64, 64)).astype(float)
   ...: nonzeros = np.count_nonzero(tmp, axis=0)
   ...: 

In [7]: %time slow_result = slow(tmp, c, nonzeros)
CPU times: user 488 ms, sys: 16 ms, total: 504 ms
Wall time: 553 ms

In [8]: %time fast_result = fast(tmp, c, nonzeros)
CPU times: user 4 ms, sys: 4 ms, total: 8 ms
Wall time: 16.4 ms

In [9]: np.allclose(slow_result, fast_result)
Out[9]: True

或者,您通常可以将 np.where 替换为乘法,例如 tmp + (tmp > 0) * (c/nonzeros)

修改代码以防止出现非零元素为零的情况留作读者练习。 ;-)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-01
    相关资源
    最近更新 更多