How to transform negative elements to zero without a loop?
a = a.clip(min=0)
I would do this:
a[a < 0] = 0
If you want to keep the original a
and only set the negative elements to zero in a copy, you can copy the array first:
c = a.copy()
c[c < 0] = 0
Another trick is to use multiplication. This actually seems to be much faster than every other method here. For example
b = a*(a>0) # copies data
or
a *= (a>0) # in-place zero-ing
I ran tests with timeit, pre-calculating the the < and > because some of these modify in-place and that would greatly effect results. In all cases a
was np.random.uniform(-1, 1, 20000000)
but with negatives already set to 0 but L = a < 0
and G = a > 0
before a
was changed. The clip
is relatively negatively impacted since it doesn't get to use L
or G
(however calculating those on the same machine took only 17ms each, so it is not the major cause of speed difference).
%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`)
When choosing to penalize the in-place methods instead of clip
, the following timings come up:
%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
Non in-place methods are penalized by 20ms (the time required to calculate a>0
or a<0
) and the in-place methods are penalize 73-83 ms (so it takes about 53-63ms to do b.copy()
).
Overall the multiplication methods are much faster than clip
. If not in-place, it is 1.5x faster. If you can do it in-place then it is 2.75x faster.
Use where
a[numpy.where(a<0)] = 0