Ответ 1
a = a.clip(min=0)
Если у меня есть массив вроде
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
a = a.clip(min=0)
Я бы сделал это:
a[a < 0] = 0
Если вы хотите сохранить исходный a
и только установить отрицательные элементы в ноль в копии, вы можете сначала скопировать массив:
c = a.copy()
c[c < 0] = 0
Другим трюком является использование умножения. На самом деле это выглядит намного быстрее, чем любой другой метод. Например
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 мс (поэтому требуется около 53-63 мс для выполнения b.copy()
).
В целом методы умножения намного быстрее, чем clip
. Если не на месте, он быстрее 1,5x. Если вы можете сделать это на месте, это быстрее 2.75x.
Используйте where
a[numpy.where(a<0)] = 0