Другой трюк заключается в использовании умножения. Это на самом деле кажется намного быстрее, чем любой другой метод здесь. Например
b = a*(a>0) # copies data
или
a *= (a>0) # in-place zero-ing
Я запустил тесты со временем, предварительно рассчитав <и>, потому что некоторые из них модифицируют на месте, и это сильно повлияет на результаты. Во всех случаях a
было np.random.uniform(-1, 1, 20000000)
, но с отрицаниями, уже установленными на 0, но L = a < 0
и G = a > 0
до того, как a
было изменено. На 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 мс (поэтому для выполнения * 1024 требуется около 53-63 мс) *).
В целом методы умножения намного быстрее, чем clip
. Если не на месте, это будет 1,5x быстрее. Если вы можете сделать это на месте, то это будет 2,75x быстрее.