如何在不使用循环的情况下将负元素变为零?
如果我有一个数组,比如说:
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.38629984856
- 0.516846179962 <- 用a.clip(min=0)会更快;
- 0.615426063538
- 0.944557905197
- 51.7364809513
6 个回答
还有一个小技巧就是使用乘法。实际上,这种方法比这里的其他方法都要快很多。例如:
b = a*(a>0) # copies data
或者:
a *= (a>0) # in-place zero-ing
我用timeit进行了测试,事先计算了<和>,因为有些方法是直接在原地修改的,这会大大影响结果。在所有情况下,a
都是通过np.random.uniform(-1, 1, 20000000)
生成的,但负数已经被设置为0,之后才计算L = a < 0
和G = a > 0
。由于clip
没有使用L
或G
,所以它的性能受到了一定影响(不过在同一台机器上计算这些只花了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
非原地的方法会多花20毫秒(这是计算a>0
或a<0
所需的时间),而原地的方法则会多花73到83毫秒(所以执行b.copy()
大约需要53到63毫秒)。
总体来说,乘法的方法比clip
快很多。如果不是原地修改,速度快1.5倍;如果可以原地修改,速度快2.75倍。
我会这样做:
a[a < 0] = 0
如果你想保留原来的 a
数组,并且只把负数的元素在一个副本中设置为零,你可以先复制这个数组:
c = a.copy()
c[c < 0] = 0
在编程中,有时候我们需要处理一些数据,比如从一个地方获取数据,然后在另一个地方使用这些数据。这个过程就像是把水从一个水桶倒到另一个水桶里。
有些时候,我们会遇到一些问题,比如数据的格式不对,或者数据不完整。这就像是你在倒水的时候,发现水桶有个洞,水流出来了,导致你倒不满。
为了避免这些问题,我们可以使用一些工具和方法来确保数据的质量。就像在倒水之前,先检查水桶有没有破损,确保水能顺利倒入。
总之,处理数据就像是一个小实验,我们需要仔细观察,确保每一步都能顺利进行,这样才能得到我们想要的结果。
a = a.clip(min=0)