如何在没有循环的情况下将负元素转换为零?

时间:2010-08-02 21:18:24

标签: python numpy

如果我有像

这样的数组
a = np.array([2, 3, -1, -4, 3])

我想将所有负面元素设置为零:[2, 3, 0, 0, 3]。如何用numpy做一个没有明确的?我需要在计算中使用修改后的a,例如

c = a * b

其中b是另一个与原始a

长度相同的数组

结论

import numpy as np
from time import time

a = np.random.uniform(-1, 1, 20000000)
t = time(); b = np.where(a>0, a, 0); print ("1. ", time() - t)
a = np.random.uniform(-1, 1, 20000000)
t = time(); b = a.clip(min=0); print ("2. ", time() - t)
a = np.random.uniform(-1, 1, 20000000)
t = time(); a[a < 0] = 0; print ("3. ", time() - t)
a = np.random.uniform(-1, 1, 20000000)
t = time(); a[np.where(a<0)] = 0; print ("4. ", time() - t)
a = np.random.uniform(-1, 1, 20000000)
t = time(); b = [max(x, 0) for x in a]; print ("5. ", time() - t)
  1. 1.38629984856
  2. 0.516846179962&lt; - 更快a.clip(min = 0);
  3. 0.615426063538
  4. 0.944557905197
  5. 51.7364809513

5 个答案:

答案 0 :(得分:76)

a = a.clip(min=0)

答案 1 :(得分:12)

我会这样做:

a[a < 0] = 0

如果您想保留原始a并且只在副本中将负元素设置为零,则可以先复制数组:

c = a.copy()
c[c < 0] = 0

答案 2 :(得分:7)

另一个技巧是使用乘法。这实际上似乎比这里的其他方法快得多。例如

b = a*(a>0) # copies data

a *= (a>0) # in-place zero-ing

我用timeit运行测试,预先计算&lt;和&gt;因为其中一些就地修改并且会极大地影响结果。在所有情况下,a均为np.random.uniform(-1, 1, 20000000)但已将负数设置为0,但在L = a < 0更改之前G = a > 0aclip受到相对负面影响,因为它无法使用LG(但是在同一台机器上计算它们每个只花费17毫秒,因此它不是主要原因速差)。

%timeit b = np.where(G, a, 0)  # 132ms  copies
%timeit b = a.clip(min=0)      # 165ms  copies
%timeit a[L] = 0               # 158ms  in-place
%timeit a[np.where(L)] = 0     # 122ms  in-place
%timeit b = a*G                # 87.4ms copies
%timeit np.multiply(a,G,a)     # 40.1ms in-place (normal code would use `a*=G`)

当选择惩罚就地方法而不是clip时,会出现以下时间:

%timeit b = np.where(a>0, a, 0)             # 152ms
%timeit b = a.clip(min=0)                   # 165ms
%timeit b = a.copy(); b[a<0] = 0            # 231ms
%timeit b = a.copy(); b[np.where(a<0)] = 0  # 205ms
%timeit b = a*(a>0)                         # 108ms
%timeit b = a.copy(); b*=a>0                # 121ms

非就地方法会受到20ms的惩罚(计算a>0a<0所需的时间),就地方法会受到73-83 ms的惩罚(因此需要大约53-63ms)做b.copy())。

总体而言,乘法方法比clip快得多。如果不是就地,则 1.5x 更快。如果你可以就地进行,那么 2.75x 会更快。

答案 3 :(得分:4)

使用where

a[numpy.where(a<0)] = 0

答案 4 :(得分:0)

为了全面起见,我想添加Heaviside函数(或step函数)的使用,以实现类似的结果,如下所示:

让我们说连续性

  [Authorize]
  public class NotifyHub : Hub {
    private readonly MyApi _api;

    public NotifyHub(MyApi api) {
      _api = api;
      _api.Notification += OnNotification;
    }

    private async void OnNotification(object sender, Notification notification) {
      //  can access Context.User here
      await Clients.All.SendAsync("Notification", notification);
    }
  }

然后使用步进功能np.heaviside()可以尝试

a = np.array([2, 3, -1, -4, 3])

请注意此操作中的一些有趣内容,因为负号得以保留!我会说,对于大多数情况不是很理想。

然后可以通过以下方式更正

b = a * np.heaviside(a, 0)

因此,在不调用某些循环的情况下,这样做可能是很长的路要走。

相关问题