Автор оригинала: Tirthajyoti Sarkar.
NumPy-это чистое золото. Он быстр, прост в освоении, многофункциональен и, следовательно, лежит в основе почти всех научно-популярных пакетов во вселенной Python (включая SciPy и Pandas, два наиболее широко используемых пакета для науки о данных и статистического моделирования). В этой статье давайте кратко обсудим две интересные особенности NumPy, а именно: мутация путем нарезки и трансляции.
Мутация путем нарезки
Оказывается, что если вы используете простое срезание/индексирование с помощью NumPy для создания подмассива, подмассив фактически указывает на основной массив. Проще говоря, диаграмма в памяти выглядит следующим образом,
Поэтому, если срезанный массив изменяется, это влияет и на родительский массив. Это может быть полезной функцией для распространения желаемой цепочки вверх по пищевой цепочке, но иногда также может быть неприятностью, когда вы сохраняете неизменным основной набор данных и вносите изменения только в подмножество. В этих случаях вам необходимо явно вызвать метод np.array , чтобы определить срезанный массив, а не просто срезать его путем индексации. Следующий код иллюстрирует этот момент,
Иллюстративный код
mat = np.array([[11,12,13],[21,22,23],[31,32,33]]) print("Original matrix") print(mat) # Simple Indexing mat_slice = mat[:2,:2] print ("\nSliced matrix") print(mat_slice) print ("\nChange the sliced matrix") mat_slice[0,0] = 1000 print (mat_slice) print("\nBut the original matrix? WHOA! It got changed too!") print(mat)
Результат выглядит следующим образом,
Original matrix [[11 12 13] [21 22 23] [31 32 33]] Sliced matrix [[11 12] [21 22]] Change the sliced matrix [[1000 12] [21 22]] But the original matrix? WHOA! It got changed too! [[1000 12 13] [21 22 23] [31 32 33]]
Чтобы этого не произошло, вот что вы должны сделать,
# Little different way to create a copy of the sliced matrix print ("\nDoing it again little differently now...\n") mat = np.array([[11,12,13],[21,22,23],[31,32,33]]) print("Original matrix") print(mat) # Notice the np.array method mat_slice = np.array(mat[:2,:2]) print ("\nSliced matrix") print(mat_slice) print ("\nChange the sliced matrix") mat_slice[0,0] = 1000 print (mat_slice) print("\nBut the original matrix? NO CHANGE this time:)") print(mat)
Теперь исходная матрица не мутирует из-за каких-либо изменений в подматрице,
Original matrix [[11 12 13] [21 22 23] [31 32 33]] Sliced matrix [[11 12] [21 22]] Change the sliced matrix [[1000 12] [21 22]] But the original matrix? NO CHANGE this time:) [[11 12 13] [21 22 23] [31 32 33]]
Трансляция
Операции NumPy обычно выполняются с парами массивов по элементам. В общем случае два массива должны иметь точно такую же форму (или для умножения матрицы внутреннее измерение должно соответствовать).
Правило вещания NumPy ослабляет это ограничение, когда формы массивов удовлетворяют определенным ограничениям . При работе с двумя массивами NumPy сравнивает их формы по элементам. Он начинается с конечных размеров и продвигается вперед. Два измерения совместимы, когда
- они равны, или
- один из них-1
Если эти условия не выполняются, возникает исключение ValueError: кадры не выровнены , указывающее, что массивы имеют несовместимые формы. Размер результирующего массива-это максимальный размер по каждому измерению входных массивов.
Для получения более подробной информации, пожалуйста, посмотрите: https://docs.scipy.org/doc/numpy-1.10.1/user/basics.broadcasting.html .
Следующий блок кода иллюстрирует идею шаг за шагом,
Инициализируйте матрицу “старт” с нулями
start = np.zeros((4,3)) print(start) [[0. 0. 0.] [0. 0. 0.] [0. 0. 0.] [0. 0. 0.]]
Создайте матрицу строк (вектор),
# create a rank 1 ndarray with 3 values add_rows = np.array([1, 0, 2]) print(add_rows) [1 0 2]
Добавьте нулевую матрицу (4×3) к вектору (1×3). Автоматически вектор 1×3 дублируется 4 раза, чтобы соответствовать размеру строки нулевой матрицы , и эти значения добавляются в матрицу 4×3.
y = start + add_rows # add to each row of 'start' print(y) [[1. 0. 2.] [1. 0. 2.] [1. 0. 2.] [1. 0. 2.]]
Создайте матрицу столбцов (вектор),
# create an ndarray which is 4 x 1 to broadcast across columns add_cols = np.array([[0,1,2,3]]) add_cols = add_cols.T print(add_cols) [[0] [1] [2] [3]]
Добавьте нулевую матрицу (4×3) к вектору (4×1). Автоматически вектор 4×1 дублируется 3 раза, чтобы соответствовать размеру столбца нулевой матрицы , и эти значения добавляются в матрицу 4×3.
# add to each column of 'start' using broadcasting y = start + add_cols print(y) [[0. 0. 0.] [1. 1. 1.] [2. 2. 2.] [3. 3. 3.]]
Наконец, скаляр обрабатывается как матрица 1×1 и дублируется точно до размера аддитивной матрицы для выполнения операции.
# this will just broadcast in both dimensions add_scalar = np.array([100]) print(start+add_scalar) [[100. 100. 100.] [100. 100. 100.] [100. 100. 100.] [100. 100. 100.]]
Полезность широковещания лучше всего реализуется, когда вы используете массивы NumPy для написания векторизованного кода для алгоритма, такого как градиентный спуск . Эндрю Нг |/проводит полную видеолекцию |/объясняя концепцию вещания на Python в своем новом курсе глубокого обучения. Это делает реализацию алгоритма прямого и обратного распространения для глубокой нейронной сети относительно безболезненной.
Вы также можете посмотреть это видео о демонстрации функции вещания…
Видео с объяснением трансляции Numpy
Если у вас есть какие-либо вопросы или идеи, которыми вы хотите поделиться, пожалуйста, свяжитесь с автором по адресу tirthajyoti[AT]gmail.com . Также вы можете проверить репозитории автора GitHub на наличие других интересных фрагментов кода в Python, R или MATLAB и ресурсах машинного обучения. Вы также можете следовать за мной в LinkedIn .