Что такое векторизация?

Что значит векторизовать циклы for в Python? Есть ли другой способ записи вложенных циклов for?

Я новичок в Python и в своих исследованиях я всегда сталкиваюсь с библиотекой NumPy.

Ответ 1

Python for циклов по своей сути медленнее, чем их аналог C.

Вот почему numpy предлагает векторизованные действия на массивах numpy. Он толкает цикл for вы обычно делаете на Python до уровня C, что намного быстрее. numpy предлагает векторизованные ("C level for loop") альтернативы вещам, которые в противном случае должны выполняться по-разному ("Уровень Python for цикла").

import numpy as np
from timeit import Timer

li = list(range(500000))
nump_arr = np.array(li)

def python_for():
    return [num + 1 for num in li]

def numpy_add():
    return nump_arr + 1

print(min(Timer(python_for).repeat(10, 10)))
print(min(Timer(numpy_add).repeat(10, 10)))

#  0.725692612368003
#  0.010465986942008954

Носифицированное добавление numpy было в x70 раз быстрее.

Ответ 2

Здесь определение от Уэса МакКинни:

Массивы важны, потому что они позволяют вам выражать пакетные операции с данными без записи каких-либо циклов. Обычно это называется векторизация. Любые арифметические операции между массивами одинакового размера применяют операцию elementwise.

Векторизованная версия:

>>> import numpy as np
>>> arr = np.array([[1., 2., 3.], [4., 5., 6.]])
>>> arr * arr
array([[  1.,   4.,   9.],
       [ 16.,  25.,  36.]])

То же самое с петлями в собственном Python (вложенном) списке:

>>> arr = arr.tolist()
>>> res = [[0., 0., 0.], [0., 0., 0.]]
>>> for idx1, row in enumerate(arr):
        for idx2, val2 in enumerate(row):
            res[idx1][idx2] = val2 * val2
>>> res
[[1.0, 4.0, 9.0], [16.0, 25.0, 36.0]]

Как эти две операции сравниваются? Версия NumPy занимает 436 нс; версия Python занимает 3,52 мкс (3520 нс). Эта большая разница в "малых" временах называется микроизверением, и это становится важным, когда вы работаете с большими данными или повторяете операции тысячи или миллионы раз.