Почему использование numpy.nonzero намного быстрее, чем циклическое выполнение массива numpy? - PullRequest
0 голосов
/ 20 декабря 2018

Давайте создадим простой массив из 10 миллионов bools со всеми значениями, инициализированными в True

n=10000000
sample = np.ones(n, dtype=bool)

Далее мы установим несколько значений в False

sample[1] = sample[5] = sample[12] = sample[25] = sample[50] = False

Число Trueзначения теперь n-5 = 9999995

Мы можем посчитать количество истинных значений, либо просматривая массив, либо используя np.nonzero

Первый метод занимает около 30 секунд на моем MacBookкак видно из

    !date
    sum=0
    for i in range(n):  
       if sample[i] == True:
          sum=sum+1
    print(sum)
    !date

Thu Dec 20 01:31:34 EST 2018
9999995
Thu Dec 20 01:32:02 EST 2018

В то время как второй метод занимает меньше секунды

!date
print(len(np.zero(sample)[0]))
!date

Thu Dec 20 01:33:05 EST 2018
9999995
Thu Dec 20 01:33:05 EST 2018

Когда массив равен 1 миллиарду бул, снова меньше секунды, тогда как цикл занимает околополчаса.

Почему такая огромная разница?Поддерживает ли метод numpy.nonzero какие-либо метаданные, к которым имеет доступ len? *

1 Ответ

0 голосов
/ 20 декабря 2018

В вашем первом примере есть цикл Python, и в каждой итерации необходимо построить логический объект Python (28 байт) из низкоуровневого логического (1 байт) массива numpy, а затем (если Python не умнее, чемЯ думаю, что это так) другой логический объект создан для хранения результата бесполезного сравнения логического числа с True (бесполезно, потому что if x: всегда совпадает с if x == True:, если x является логическим значением).Также ведутся вычисления относительно вашего счетчика, i.

Ваш второй пример почти полностью происходит в нативном коде, а не в Python.Неявный цикл кодируется на низкоуровневом языке, его счетчик увеличивается с помощью одной инструкции машинного кода, доступ к данным является настолько прямым, насколько можно себе представить.Вы попадаете в Python только несколько раз: один раз, чтобы обернуть вновь созданный массив в объекте Python в конце np.zero, один раз, чтобы создать целое число Python для результата len.

То естьЕдинственное отличие: Python против нативного.

...