NumPy в Python. Часть 1
Доброго времени суток, Хабр. Запускаю цикл статей, которые являются переводом небольшого мана по numpy, ссылочка. Приятного чтения.
Введение
NumPy это open-source модуль для python, который предоставляет общие математические и числовые операции в виде пре-скомпилированных, быстрых функций. Они объединяются в высокоуровневые пакеты. Они обеспечивают функционал, который можно сравнить с функционалом MatLab. NumPy (Numeric Python) предоставляет базовые методы для манипуляции с большими массивами и матрицами. SciPy (Scientific Python) расширяет функционал numpy огромной коллекцией полезных алгоритмов, таких как минимизация, преобразование Фурье, регрессия, и другие прикладные математические техники.
Установка
Если у вас есть Python(x, y) (Примечание переводчика: Python(x, y), это дистрибутив свободного научного и инженерного программного обеспечения для численных расчётов, анализа и визуализации данных на основе языка программирования Python и большого числа модулей (библиотек)) на платформе Windows, то вы готовы начинать. Если же нет, то после установки python, вам нужно установить пакеты самостоятельно, сначала NumPy потом SciPy. Установка доступна здесь. Следуйте установке на странице, там всё предельно понятно.
Немного дополнительной информации
Сообщество NumPy и SciPy поддерживает онлайн руководство, включающие гайды и туториалы, тут: docs.scipy.org/doc.
Импорт модуля numpy
Есть несколько путей импорта. Стандартный метод это — использовать простое выражение:
>>> import numpy
Тем не менее, для большого количества вызовов функций numpy, становится утомительно писать numpy.X снова и снова. Вместо этого намного легче сделать это так:
>>> import numpy as np
Это выражение позволяет нам получать доступ к numpy объектам используя np.X вместо numpy.X. Также можно импортировать numpy прямо в используемое пространство имен, чтобы вообще не использовать функции через точку, а вызывать их напрямую:
>>> from numpy import *
Однако, этот вариант не приветствуется в программировании на python, так как убирает некоторые полезные структуры, которые модуль предоставляет. До конца этого туториала мы будем использовать второй вариант импорта (import numpy as np).
Массивы
Главной особенностью numpy является объект array. Массивы схожи со списками в python, исключая тот факт, что элементы массива должны иметь одинаковый тип данных, как float и int. С массивами можно проводить числовые операции с большим объемом информации в разы быстрее и, главное, намного эффективнее чем со списками.
Создание массива из списка:
a = np.array([1, 4, 5, 8], float) >>> a array([ 1., 4., 5., 8.]) >>> type(a)
Здесь функция array принимает два аргумента: список для конвертации в массив и тип для каждого элемента. Ко всем элементам можно получить доступ и манипулировать ими так же, как вы бы это делали с обычными списками:
>>> a[:2] array([ 1., 4.]) >>> a[3] 8.0 >>> a[0] = 5. >>> a array([ 5., 4., 5., 8.])
Массивы могут быть и многомерными. В отличии от списков можно использовать запятые в скобках. Вот пример двумерного массива (матрица):
>>> a = np.array([[1, 2, 3], [4, 5, 6]], float) >>> a array([[ 1., 2., 3.], [ 4., 5., 6.]]) >>> a[0,0] 1.0 >>> a[0,1] 2.0
Array slicing работает с многомерными массивами аналогично, как и с одномерными, применяя каждый срез, как фильтр для установленного измерения. Используйте «:» в измерении для указывания использования всех элементов этого измерения:
>>> a = np.array([[1, 2, 3], [4, 5, 6]], float) >>> a[1,:] array([ 4., 5., 6.]) >>> a[:,2] array([ 3., 6.]) >>> a[-1:, -2:] array([[ 5., 6.]])
Метод shape возвращает количество строк и столбцов в матрице:
>>> a.shape (2, 3)
Метод dtype возвращает тип переменных, хранящихся в массиве:
>>> a.dtype dtype('float64')
Тут float64, это числовой тип данных в numpy, который используется для хранения вещественных чисел двойной точности. Так же как float в Python.
Метод len возвращает длину первого измерения (оси):
a = np.array([[1, 2, 3], [4, 5, 6]], float) >>> len(a) 2
Метод in используется для проверки на наличие элемента в массиве:
>>> a = np.array([[1, 2, 3], [4, 5, 6]], float) >>> 2 in a True >>> 0 in a False
Массивы можно переформировать при помощи метода, который задает новый многомерный массив. Следуя следующему примеру, мы переформатируем одномерный массив из десяти элементов во двумерный массив, состоящий из пяти строк и двух столбцов:
>>> a = np.array(range(10), float) >>> a array([ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9.]) >>> a = a.reshape((5, 2)) >>> a array([[ 0., 1.], [ 2., 3.], [ 4., 5.], [ 6., 7.], [ 8., 9.]]) >>> a.shape (5, 2)
Обратите внимание, метод reshape создает новый массив, а не модифицирует оригинальный.
Имейте ввиду, связывание имен в python работает и с массивами. Метод copy используется для создания копии существующего массива в памяти:
>>> a = np.array([1, 2, 3], float) >>> b = a >>> c = a.copy() >>> a[0] = 0 >>> a array([0., 2., 3.]) >>> b array([0., 2., 3.]) >>> c array([1., 2., 3.])
Списки можно тоже создавать с массивов:
>>> a = np.array([1, 2, 3], float) >>> a.tolist() [1.0, 2.0, 3.0] >>> list(a) [1.0, 2.0, 3.0]
Можно также переконвертировать массив в бинарную строку (то есть, не human-readable форму). Используйте метод tostring для этого. Метод fromstring работает в для обратного преобразования. Эти операции иногда полезны для сохранения большого количества данных в файлах, которые могут быть считаны в будущем.
>>> a = array([1, 2, 3], float) >>> s = a.tostring() >>> s '\x00\x00\x00\x00\x00\x00\xf0?\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x00\x00\x00\x08@' >>> np.fromstring(s) array([ 1., 2., 3.])
Заполнение массива одинаковым значением.
>>> a = array([1, 2, 3], float) >>> a array([ 1., 2., 3.]) >>> a.fill(0) >>> a array([ 0., 0., 0.])
Транспонирование массивов также возможно, при этом создается новый массив:
>>> a = np.array(range(6), float).reshape((2, 3)) >>> a array([[ 0., 1., 2.], [ 3., 4., 5.]]) >>> a.transpose() array([[ 0., 3.], [ 1., 4.], [ 2., 5.]])
Многомерный массив можно переконвертировать в одномерный при помощи метода flatten:
>>> a = np.array([[1, 2, 3], [4, 5, 6]], float) >>> a array([[ 1., 2., 3.], [ 4., 5., 6.]]) >>> a.flatten() array([ 1., 2., 3., 4., 5., 6.])
Два или больше массивов можно сконкатенировать при помощи метода concatenate:
>>> a = np.array([1,2], float) >>> b = np.array([3,4,5,6], float) >>> c = np.array([7,8,9], float) >>> np.concatenate((a, b, c)) array([1., 2., 3., 4., 5., 6., 7., 8., 9.])
Если массив не одномерный, можно задать ось, по которой будет происходить соединение. По умолчанию (не задавая значения оси), соединение будет происходить по первому измерению:
>>> a = np.array([[1, 2], [3, 4]], float) >>> b = np.array([[5, 6], [7,8]], float) >>> np.concatenate((a,b)) array([[ 1., 2.], [ 3., 4.], [ 5., 6.], [ 7., 8.]]) >>> np.concatenate((a,b), axis=0) array([[ 1., 2.], [ 3., 4.], [ 5., 6.], [ 7., 8.]]) >>> np.concatenate((a,b), axis=1) array([[ 1., 2., 5., 6.], [ 3., 4., 7., 8.]])
В заключении, размерность массива может быть увеличена при использовании константы newaxis в квадратных скобках:
>>> a = np.array([1, 2, 3], float) >>> a array([1., 2., 3.]) >>> a[:,np.newaxis] array([[ 1.], [ 2.], [ 3.]]) >>> a[:,np.newaxis].shape (3,1) >>> b[np.newaxis,:] array([[ 1., 2., 3.]]) >>> b[np.newaxis,:].shape (1,3)
Заметьте, тут каждый массив двумерный; созданный при помощи newaxis имеет размерность один. Метод newaxis подходит для удобного создания надлежаще-мерных массивов в векторной и матричной математике.
На этом у нас конец первой части перевода. Спасибо за внимание.
NumPy, часть 1: начало работы
NumPy — это библиотека языка Python, добавляющая поддержку больших многомерных массивов и матриц, вместе с большой библиотекой высокоуровневых (и очень быстрых) математических функций для операций с этими массивами.
Установка NumPy
На linux — пакет python3-numpy (или аналогичный для вашей системы), или через pip. Ну или же собирать из исходников https://sourceforge.net/projects/numpy/files/NumPy/.
На Windows на том же сайте есть exe установщики. Или, если возникают проблемы, рекомендую ещё хороший сборник библиотек http://www.lfd.uci.edu/~gohlke/pythonlibs/#numpy.
Начинаем работу
Основным объектом NumPy является однородный многомерный массив (в numpy называется numpy.ndarray). Это многомерный массив элементов (обычно чисел), одного типа.
Наиболее важные атрибуты объектов ndarray:
ndarray.ndim — число измерений (чаще их называют «оси») массива.
ndarray.shape — размеры массива, его форма. Это кортеж натуральных чисел, показывающий длину массива по каждой оси. Для матрицы из n строк и m столбов, shape будет (n,m). Число элементов кортежа shape равно ndim.
ndarray.size — количество элементов массива. Очевидно, равно произведению всех элементов атрибута shape.
ndarray.dtype — объект, описывающий тип элементов массива. Можно определить dtype, используя стандартные типы данных Python. NumPy здесь предоставляет целый букет возможностей, как встроенных, например: bool_, character, int8, int16, int32, int64, float8, float16, float32, float64, complex64, object_, так и возможность определить собственные типы данных, в том числе и составные.
ndarray.itemsize — размер каждого элемента массива в байтах.
ndarray.data — буфер, содержащий фактические элементы массива. Обычно не нужно использовать этот атрибут, так как обращаться к элементам массива проще всего с помощью индексов.
Создание массивов
В NumPy существует много способов создать массив. Один из наиболее простых — создать массив из обычных списков или кортежей Python, используя функцию numpy.array() (запомните: array — функция, создающая объект типа ndarray):
Функция array() трансформирует вложенные последовательности в многомерные массивы. Тип элементов массива зависит от типа элементов исходной последовательности (но можно и переопределить его в момент создания).
Можно также переопределить тип в момент создания:
Функция array() не единственная функция для создания массивов. Обычно элементы массива вначале неизвестны, а массив, в котором они будут храниться, уже нужен. Поэтому имеется несколько функций для того, чтобы создавать массивы с каким-то исходным содержимым (по умолчанию тип создаваемого массива — float64).
Функция zeros() создает массив из нулей, а функция ones() — массив из единиц. Обе функции принимают кортеж с размерами, и аргумент dtype:
Функция eye() создаёт единичную матрицу (двумерный массив)
Функция empty() создает массив без его заполнения. Исходное содержимое случайно и зависит от состояния памяти на момент создания массива (то есть от того мусора, что в ней хранится):
Для создания последовательностей чисел, в NumPy имеется функция arange(), аналогичная встроенной в Python range(), только вместо списков она возвращает массивы, и принимает не только целые значения:
Вообще, при использовании arange() с аргументами типа float, сложно быть уверенным в том, сколько элементов будет получено (из-за ограничения точности чисел с плавающей запятой). Поэтому, в таких случаях обычно лучше использовать функцию linspace(), которая вместо шага в качестве одного из аргументов принимает число, равное количеству нужных элементов:
fromfunction(): применяет функцию ко всем комбинациям индексов
Печать массивов
Если массив слишком большой, чтобы его печатать, NumPy автоматически скрывает центральную часть массива и выводит только его уголки.
Если вам действительно нужно увидеть весь массив, используйте функцию numpy.set_printoptions:
И вообще, с помощью этой функции можно настроить печать массивов "под себя". Функция numpy.set_printoptions принимает несколько аргументов:
precision : количество отображаемых цифр после запятой (по умолчанию 8).
threshold : количество элементов в массиве, вызывающее обрезание элементов (по умолчанию 1000).
edgeitems : количество элементов в начале и в конце каждой размерности массива (по умолчанию 3).
linewidth : количество символов в строке, после которых осуществляется перенос (по умолчанию 75).
suppress : если True, не печатает маленькие значения в scientific notation (по умолчанию False).
nanstr : строковое представление NaN (по умолчанию ‘nan’).
infstr : строковое представление inf (по умолчанию ‘inf’).
formatter : позволяет более тонко управлять печатью массивов. Здесь я его рассматривать не буду, можете почитать здесь (на английском).
И вообще, пользуйтесь официальной документацией по numpy, а в этом пособии я постараюсь описать всё необходимое. В следующей части мы рассмотрим базовые операции над массивами.
Подписывайтесь, чтобы не пропустить 🙂
Для вставки кода на Python в комментарий заключайте его в теги
NumPy: матрицы и операции над ними
В этом ноутбуке из сторонних библиотек нам понадобится только NumPy. Для удобства импортируем ее под более коротким именем:
import numpy as np
1. Создание матриц
Приведем несколько способов создания матриц в NumPy.
Самый простой способ — с помощью функции numpy.array(list, dtype=None, . ).
В качестве первого аргумента ей надо передать итерируемый объект, элементами которого являются другие итерируемые объекты одинаковой длины и содержащие данные одинакового типа.
Второй аргумент является опциональным и определяет тип данных матрицы. Его можно не задавать, тогда тип данных будет определен из типа элементов первого аргумента. При задании этого параметра будет произведена попытка приведения типов.
Например, матрицу из списка списков целых чисел можно создать следующим образом:
a = np.array([1, 2, 3]) # Создаем одномерный массив print(type(a)) # Prints "" print(a.shape) # Prints "(3,)" - кортеж с размерностями print(a[0], a[1], a[2]) # Prints "1 2 3" a[0] = 5 # Изменяем значение элемента массива print(a) # Prints "[5, 2, 3]" b = np.array([[1,2,3],[4,5,6]]) # Создаем двухмерный массив print(b.shape) # Prints "(2, 3)" print(b[0, 0], b[0, 1], b[1, 0]) # Prints "1 2 4" print(np.arange(1, 5)) #Cоздает вектор с эелементами от 1 до 4
(3,) 1 2 3 [5 2 3] (2, 3) 1 2 4 [1 2 3 4]
matrix = np.array([[1, 2, 3], [2, 5, 6], [6, 7, 4]]) print ("Матрица:\n", matrix)
Матрица: [[1 2 3] [2 5 6] [6 7 4]]
Второй способ создания — с помощью встроенных функций numpy.eye(N, M=None, . ), numpy.zeros(shape, . ), numpy.ones(shape, . ).
Первая функция создает единичную матрицу размера N×M ; если M не задан, то M = N .
Вторая и третья функции создают матрицы, состоящие целиком из нулей или единиц соответственно. В качестве первого аргумента необходимо задать размерность массива — кортеж целых чисел. В двумерном случае это набор из двух чисел: количество строк и столбцов матрицы.
Примеры:
b = np.eye(5) print ("Единичная матрица:\n", b)
Единичная матрица: [[1. 0. 0. 0. 0.] [0. 1. 0. 0. 0.] [0. 0. 1. 0. 0.] [0. 0. 0. 1. 0.] [0. 0. 0. 0. 1.]]
c = np.ones((7, 5)) print ("Матрица, состоящая из одних единиц:\n", c)
Матрица, состоящая из одних единиц: [[1. 1. 1. 1. 1.] [1. 1. 1. 1. 1.] [1. 1. 1. 1. 1.] [1. 1. 1. 1. 1.] [1. 1. 1. 1. 1.] [1. 1. 1. 1. 1.] [1. 1. 1. 1. 1.]]
d = np.full((2,2), 7) # Создает матрицу (1, 2) заполненую заданным значением print(d) # Prints "[[ 7. 7.] # [ 7. 7.]]" e = np.random.random((2,2)) # Создает еденичную матрицу (2, 2) заполненую случаными числами (0, 1) print(e) # Might print "[[ 0.91940167 0.08143941] # [ 0.68744134 0.87236687]]"
[[7 7] [7 7]] [[0.25744383 0.48056466] [0.13767881 0.40578168]]
Обратите внимание: размерность массива задается не двумя аргументами функции, а одним — кортежем!
Вот так — np.ones(7, 5) — создать массив не получится, так как функции в качестве параметра shape передается 7, а не кортеж (7, 5).
И, наконец, третий способ — с помощью функции numpy.arange([start, ]stop, [step, ], . ), которая создает одномерный массив последовательных чисел из промежутка [start, stop) с заданным шагом step, и метода array.reshape(shape).
Параметр shape, как и в предыдущем примере, задает размерность матрицы (кортеж чисел). Логика работы метода ясна из следующего примера:
v = np.arange(0, 24, 2) print ("Вектор-столбец:\n", v)
Вектор-столбец: [ 0 2 4 6 8 10 12 14 16 18 20 22]
d = v.reshape((3, 4)) print ("Матрица:\n", d)
Матрица: [[ 0 2 4 6] [ 8 10 12 14] [16 18 20 22]]
Более подробно о том, как создавать массивы в NumPy, см. документацию.
2. Индексирование
Для получения элементов матрицы можно использовать несколько способов. Рассмотрим самые простые из них.
Для удобства напомним, как выглядит матрица d:
print ("Матрица:\n", d)
Матрица: [[ 0 2 4 6] [ 8 10 12 14] [16 18 20 22]]
Элемент на пересечении строки i и столбца j можно получить с помощью выражения array[i, j].
Обратите внимание: строки и столбцы нумеруются с нуля!
print ("Второй элемент третьей строки матрицы:", d[2, 1])
Второй элемент третьей строки матрицы: 18
Из матрицы можно получать целые строки или столбцы с помощью выражений array[i, :] или array[:, j] соответственно:
print ("Вторая строка матрицы d:\n", d[1, :]) print ("Четвертый столбец матрицы d:\n", d[:, 3])
Вторая строка матрицы d: [ 8 10 12 14] Четвертый столбец матрицы d: [ 6 14 22]
Еще один способ получения элементов — с помощью выражения array[list1, list2], где list1, list2 — некоторые списки целых чисел. При такой адресации одновременно просматриваются оба списка и возвращаются элементы матрицы с соответствующими координатами. Следующий пример более понятно объясняет механизм работы такого индексирования:
print ("Элементы матрицы d с координатами (1, 2) и (0, 3):\n", d[[1, 0], [2, 3]])
Элементы матрицы d с координатами (1, 2) и (0, 3): [12 6]
# Slicing # Создадим матрицу (3, 4) # [[ 1 2 3 4] # [ 5 6 7 8] # [ 9 10 11 12]] a = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]]) # Используя слайсинг, созадим матрицу b из элементов матрицы а # будем использовать 0 и 1 строку, а так же 1 и 2 столебц # [[2 3] # [6 7]] b = a[:2, 1:3] print(b) # ОБРАТИТЕ ВНИМАНИЕ НА ИЗМЕНЕНИЕ ИСХОДОЙ МАТРИЦЫ print(a[0, 1]) # Prints "2" b[0, 0] = 77 # b[0, 0] is the same piece of data as a[0, 1] print(a[0, 1]) # Prints "77"
[[2 3] [6 7]] 2 77
# Integer array indexing a = np.array([[1,2], [3, 4], [5, 6]]) print(a) print() # Пример Integer array indexing # В результате получится массив размерности (3,) # Обратите внимание, что до запятой идут индексы строк, после - столбцов print(a[[0, 1, 2], [0, 1, 0]]) # Prints "[1 4 5]" print() # По-другому пример можно записать так print(np.array([a[0, 0], a[1, 1], a[2, 0]])) # Prints "[1 4 5]"
[[1 2] [3 4] [5 6]] [1 4 5] [1 4 5]
Примеры использования слайсинга:
# Создадим новый маассив, из которого будем выбирать эллементы a = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]]) print(a) # prints "array([[ 1, 2, 3], # [ 4, 5, 6], # [ 7, 8, 9], # [10, 11, 12]])" # Создадим массив индексов b = np.array([0, 2, 0, 1]) # Выберем из каждой строки элемент с индексом из b (индекс столбца берется из b) print(a[np.arange(4), b]) # Prints "[ 1 6 7 11]" print() # Добавим к этим элементам 10 a[np.arange(4), b] += 10 print(a) # prints "array([[11, 2, 3], # [ 4, 5, 16], # [17, 8, 9], # [10, 21, 12]])
[[ 1 2 3] [ 4 5 6] [ 7 8 9] [10 11 12]] [ 1 6 7 11] [[11 2 3] [ 4 5 16] [17 8 9] [10 21 12]]
a = np.array([[1,2], [3, 4], [5, 6]]) bool_idx = (a > 2) # Найдем эллементы матрицы a, которые больше 2 # В результате получим матрицу b, такой же размерности, как и a print(bool_idx) # Prints "[[False False] print() # [ True True] # [ True True]]" # Воспользуемся полученным массивом для создания нового массива, ранга 1 print(a[bool_idx]) # Prints "[3 4 5 6]" # Аналогично print(a[a > 2]) # Prints "[3 4 5 6]"
[[False False] [ True True] [ True True]] [3 4 5 6] [3 4 5 6]
#Помните, что вы можете пользоваться сразу несколькими типами индексирования a = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]]) row_r1 = a[1, :] row_r2 = a[1:2, :] print(row_r1, row_r1.shape) # Prints "[5 6 7 8] (4,)" print(row_r2, row_r2.shape) # Prints "[[5 6 7 8]] (1, 4)"
[5 6 7 8] (4,) [[5 6 7 8]] (1, 4)
Более подробно о различных способах индексирования в массивах см. документацию.
3. Векторы, вектор-строки и вектор-столбцы
Следующие два способа задания массива кажутся одинаковыми:
a = np.array([1, 2, 3]) b = np.array([[1], [2], [3]])
Однако, на самом деле, это задание одномерного массива (то есть вектора) и двумерного массива:
print ("Вектор:\n", a) print ("Его размерность:\n", a.shape) print ("Двумерный массив:\n", b) print ("Его размерность:\n", b.shape)
Вектор: [1 2 3] Его размерность: (3,) Двумерный массив: [[1] [2] [3]] Его размерность: (3, 1)
Обратите внимание: вектор (одномерный массив) и вектор-столбец или вектор-строка (двумерные массивы) являются различными объектами в NumPy, хотя математически задают один и тот же объект. В случае одномерного массива кортеж shape состоит из одного числа и имеет вид (n,), где n — длина вектора. В случае двумерных векторов в shape присутствует еще одна размерность, равная единице.
В большинстве случаев неважно, какое представление использовать, потому что часто срабатывает приведение типов. Но некоторые операции не работают для одномерных массивов. Например, транспонирование (о нем пойдет речь ниже):
a = a.T b = b.T
print ("Вектор не изменился:\n", a) print ("Его размерность также не изменилась:\n", a.shape) print ("Транспонированный двумерный массив:\n", b) print ("Его размерность изменилась:\n", b.shape)
Вектор не изменился: [1 2 3] Его размерность также не изменилась: (3,) Транспонированный двумерный массив: [[1 2 3]] Его размерность изменилась: (1, 3)
4. Datatypes
Все элементы в массиве numpy принадлежат одному типу. В этом плане массивы ближе к C, чем к привычным вам листам питона. Numpy имеет множество встренных типов, подходящих для решения большинства задач.
x = np.array([1, 2]) # Автоматический выбор типа print(x.dtype) # Prints "int64" x = np.array([1.0, 2.0]) # Автоматический выбор типа print(x.dtype) # Prints "float64" x = np.array([1, 2], dtype=np.int64) # Принудительное выставление типа print(x.dtype) # Prints "int64"
int32 float64 int64
5. Математические операции
К массивам (матрицам) можно применять известные вам математические операции. Следут понимать, что при этом у элементов должны быть схожие размерности. Поведение в случае не совпадения размерностей хорошо описанно в документации numpy.
x = np.array([[1,2],[3,4]], dtype=np.float64) y = np.array([[5,6],[7,8]], dtype=np.float64) arr = np.array([1, 2])
# Сложение происходит поэлеметно # [[ 6.0 8.0] # [10.0 12.0]] print(x + y) print() print(np.add(x, y)) print('С числом') print(x + 1) print('C массивом другой размерности') print(x + arr)
[[ 6. 8.] [10. 12.]] [[ 6. 8.] [10. 12.]] С числом [[2. 3.] [4. 5.]] C массивом другой размерности [[2. 4.] [4. 6.]]
# Вычитание print(x - y) print(np.subtract(x, y))
[[-4. -4.] [-4. -4.]] [[-4. -4.] [-4. -4.]]
# Деление # [[ 0.2 0.33333333] # [ 0.42857143 0.5 ]] print(x / y) print(np.divide(x, y))
[[0.2 0.33333333] [0.42857143 0.5 ]] [[0.2 0.33333333] [0.42857143 0.5 ]]
# Другие функции # [[ 1. 1.41421356] # [ 1.73205081 2. ]] print(np.sqrt(x))
[[1. 1.41421356] [1.73205081 2. ]]
6. Умножение матриц и столбцов
Напоминание теории. Операция умножения определена для двух матриц, таких что число столбцов первой равно числу строк второй.
Пусть матрицы A и B таковы, что A ∈ ℝ n×k и B ∈ ℝ k×m . Произведением матриц A и B называется матрица C , такая что cij = ∑ k r = 1 airbrj , где cij — элемент матрицы C , стоящий на пересечении строки с номером i и столбца с номером j .
В NumPy произведение матриц вычисляется с помощью функции numpy.dot(a, b, . ) или с помощью метода array1.dot(array2), где array1 и array2 — перемножаемые матрицы.
a = np.array([[1, 0], [0, 1]]) b = np.array([[4, 1], [2, 2]]) r1 = np.dot(a, b) r2 = a.dot(b)
print ("Матрица A:\n", a) print ("Матрица B:\n", b) print ("Результат умножения функцией:\n", r1) print ("Результат умножения методом:\n", r2)
Матрица A: [[1 0] [0 1]] Матрица B: [[4 1] [2 2]] Результат умножения функцией: [[4 1] [2 2]] Результат умножения методом: [[4 1] [2 2]]
Матрицы в NumPy можно умножать и на векторы:
c = np.array([1, 2]) r3 = b.dot(c)
print ("Матрица:\n", b) print ("Вектор:\n", c) print ("Результат умножения:\n", r3)
Матрица: [[4 1] [2 2]] Вектор: [1 2] Результат умножения: [6 6]
Обратите внимание: операция * производит над матрицами покоординатное умножение, а не матричное!
r = a * b
print ("Матрица A:\n", a) print ("Матрица B:\n", b) print ("Результат покоординатного умножения через операцию умножения:\n", r)
Матрица A: [[1 0] [0 1]] Матрица B: [[4 1] [2 2]] Результат покоординатного умножения через операцию умножения: [[4 0] [0 2]]
Более подробно о матричном умножении в NumPy см. документацию.
7. Объединение массивов
Массивы можно Объединенять. Есть горизонтальное и вертикальное объединение.
a = np.floor(10*np.random.random((2,2))) b = np.floor(10*np.random.random((2,2))) print(a) print(b) print() print(np.vstack((a,b))) print() print(np.hstack((a,b)))
[[4. 0.] [1. 4.]] [[9. 7.] [2. 6.]] [[4. 0.] [1. 4.] [9. 7.] [2. 6.]] [[4. 0. 9. 7.] [1. 4. 2. 6.]]
Массивы можно переформировать при помощи метода, который задает новый многомерный массив. Следуя следующему примеру, мы переформатируем одномерный массив из десяти элементов во двумерный массив, состоящий из пяти строк и двух столбцов:
a = np.array(range(10), float) print(a) print() # Превратим в матрицу a = a.reshape((5, 2)) print(a) print() # Вернем обратно print(a.flatten()) # Другой вариант print(a.reshape((-1))) # Превратим в марицу (9, 1) print(a.reshape((-1, 1))) # Превратим в марицу (1, 9) print(a.reshape((1, -1)))
[0. 1. 2. 3. 4. 5. 6. 7. 8. 9.] [[0. 1.] [2. 3.] [4. 5.] [6. 7.] [8. 9.]] [0. 1. 2. 3. 4. 5. 6. 7. 8. 9.] [0. 1. 2. 3. 4. 5. 6. 7. 8. 9.] [[0.] [1.] [2.] [3.] [4.] [5.] [6.] [7.] [8.] [9.]] [[0. 1. 2. 3. 4. 5. 6. 7. 8. 9.]]
Задания: (Блок 1)
Задание 1:
Решите без использования циклов средставми NumPy (каждый пункт решается в 1-2 строчки)
- Создайте вектор с элементами от 12 до 42
- Создайте вектор из нулей длины 12, но его пятый елемент должен быть равен 1
- Создайте матрицу (3, 3), заполненую от 0 до 8
- Найдите все положительные числа в np.array([1,2,0,0,4,0])
- Умножьте матрицу размерности (5, 3) на (3, 2)
- Создайте матрицу (10, 10) так, чтобы на границе были 0, а внтури 1
- Создайте рандомный вектор и отсортируйте его
- Каков эквивалент функции enumerate для numpy массивов?
- *Создайте рандомный вектор и выполните нормализацию столбцов (из каждого столбца вычесть среднее этого столбца, из каждого столбца вычесть sd этого столбца)
- *Для заданного числа найдите ближайший к нему элемент в векторе
- *Найдите N наибольших значений в векторе
# ваш код здесь
Задание 2:
Напишите полностью векторизованный вариант
Дан трёхмерный массив, содержащий изображение, размера (height, width, numChannels), а также вектор длины numChannels. Сложить каналы изображения с указанными весами, и вернуть результат в виде матрицы размера (height, width). Считать реальное изображение можно при помощи функции scipy.misc.imread (если изображение не в формате png, установите пакет pillow: conda install pillow). Преобразуйте цветное изображение в оттенки серого, использовав коэффициенты np.array([0.299, 0.587, 0.114]).
# ваш код здесь
8. Транспонирование матриц
Напоминание теории. Транспонированной матрицей A T называется матрица, полученная из исходной матрицы A заменой строк на столбцы. Формально: элементы матрицы A T определяются как a T ij = aji , где a T ij — элемент матрицы A T , стоящий на пересечении строки с номером i и столбца с номером j .
В NumPy транспонированная матрица вычисляется с помощью функции numpy.transpose() или с помощью метода array.T, где array — нужный двумерный массив.
a = np.array([[1, 2], [3, 4]]) b = np.transpose(a) c = a.T
print ("Матрица:\n", a) print ("Транспонирование функцией:\n", b) print ("Транспонирование методом:\n", c)
Матрица: [[1 2] [3 4]] Транспонирование функцией: [[1 3] [2 4]] Транспонирование методом: [[1 3] [2 4]]
В следующих разделах активно используется модуль numpy.linalg, реализующий некоторые приложения линейной алгебры. Более подробно о функциях, описанных ниже, и различных других функциях этого модуля можно посмотреть в его документации.
9. Определитель матрицы
Напоминание теории. Для квадратных матриц существует понятие определителя.
Пусть A — квадратная матрица. Определителем (или детерминантом) матрицы A ∈ ℝ n×n назовем число
detA = ∑ α1, α2, …, αn ( − 1) N(α1, α2, …, αn) ⋅aα11⋅⋅⋅aαnn,
где α1, α2, …, αn — перестановка чисел от 1 до n , N(α1, α2, …, αn) — число инверсий в перестановке, суммирование ведется по всем возможным перестановкам длины n .
Не стоит расстраиваться, если это определение понятно не до конца — в дальнейшем в таком виде оно не понадобится.
Например, для матрицы размера 2×2 получается:
det ⎛ ⎜ ⎝ a11 a12 a21 a22 ⎞ ⎟ ⎠ = a11a22 − a12a21
Вычисление определителя матрицы по определению требует порядка n! операций, поэтому разработаны методы, которые позволяют вычислять его быстро и эффективно.
В NumPy определитель матрицы вычисляется с помощью функции numpy.linalg.det(a), где a — исходная матрица.
a = np.array([[1, 2, 1], [1, 1, 4], [2, 3, 6]], dtype=np.float32) det = np.linalg.det(a)
print ("Матрица:\n", a) print ("Определитель:\n", det)
Матрица: [[1. 2. 1.] [1. 1. 4.] [2. 3. 6.]] Определитель: -1.0
Рассмотрим одно интересное свойство определителя. Пусть у нас есть параллелограмм с углами в точках (0, 0), (c, d), (a + c, b + d), (a, b) (углы даны в порядке обхода по часовой стрелке). Тогда площадь этого параллелограмма можно вычислить как модуль определителя матрицы ⎛ ⎜ ⎝ a c b d ⎞ ⎟ ⎠ . Похожим образом можно выразить и объем параллелепипеда через определитель матрицы размера 3×3 .
10. Ранг матрицы
Напоминание теории. Рангом матрицы A называется максимальное число линейно независимых строк (столбцов) этой матрицы.
В NumPy ранг матрицы вычисляется с помощью функции numpy.linalg.matrix_rank(M, tol=None), где M — матрица, tol — параметр, отвечающий за некоторую точность вычисления. В простом случае можно его не задавать, и функция сама определит подходящее значение этого параметра.
a = np.array([[1, 2, 3], [1, 1, 1], [2, 2, 2]]) r = np.linalg.matrix_rank(a)
print ("Матрица:\n", a) print ("Ранг матрицы:", r)
Матрица: [[1 2 3] [1 1 1] [2 2 2]] Ранг матрицы: 2
С помощью вычисления ранга матрицы можно проверять линейную независимость системы векторов.
Допустим, у нас есть несколько векторов. Составим из них матрицу, где наши векторы будут являться строками. Понятно, что векторы линейно независимы тогда и только тогда, когда ранг полученной матрицы совпадает с числом векторов. Приведем пример:
a = np.array([1, 2, 3]) b = np.array([1, 1, 1]) c = np.array([2, 3, 5]) m = np.array([a, b, c])
print (np.linalg.matrix_rank(m) == m.shape[0])
True
11. Системы линейных уравнений
Напоминание теории. Системой линейных алгебраических уравнений называется система вида Ax = b , где A ∈ ℝ n×m , x ∈ ℝ m×1 , b ∈ ℝ n×1 . В случае квадратной невырожденной матрицы A решение системы единственно.
В NumPy решение такой системы можно найти с помощью функции numpy.linalg.solve(a, b), где первый аргумент — матрица A , второй — столбец b .
a = np.array([[3, 1], [1, 2]]) b = np.array([9, 8]) x = np.linalg.solve(a, b)
print ("Матрица A:\n", a) print ("Вектор b:\n", b) print ("Решение системы:\n", x)
Матрица A: [[3 1] [1 2]] Вектор b: [9 8] Решение системы: [2. 3.]
Убедимся, что вектор x действительно является решением системы:
print (a.dot(x))
Бывают случаи, когда решение системы не существует. Но хотелось бы все равно “решить” такую систему. Логичным кажется искать такой вектор x , который минимизирует выражение ‖ Ax − b ‖ 2 — так мы приблизим выражение Ax к b .
В NumPy такое псевдорешение можно искать с помощью функции numpy.linalg.lstsq(a, b, . ), где первые два аргумента такие же, как и для функции numpy.linalg.solve(). Помимо решения функция возвращает еще три значения, которые нам сейчас не понадобятся.
a = np.array([[0, 1], [1, 1], [2, 1], [3, 1]]) b = np.array([-1, 0.2, 0.9, 2.1]) x, res, r, s = np.linalg.lstsq(a, b, rcond=None)
print ("Матрица A:\n", a) print ("Вектор b:\n", b) print ("Псевдорешение системы:\n", x)
Матрица A: [[0 1] [1 1] [2 1] [3 1]] Вектор b: [-1. 0.2 0.9 2.1] Псевдорешение системы: [ 1. -0.95]
12. Обращение матриц
Напоминание теории. Для квадратных невырожденных матриц определено понятие обратной матрицы.
Пусть A — квадратная невырожденная матрица. Матрица A − 1 называется обратной матрицей к A , если
AA − 1 = A − 1 A = I,
где I — единичная матрица.
В NumPy обратные матрицы вычисляются с помощью функции numpy.linalg.inv(a), где a — исходная матрица.
a = np.array([[1, 2, 1], [1, 1, 4], [2, 3, 6]], dtype=np.float32) b = np.linalg.inv(a)
print ("Матрица A:\n", a) print ("Обратная матрица к A:\n", b) print ("Произведение A на обратную должна быть единичной:\n", a.dot(b))
Матрица A: [[1. 2. 1.] [1. 1. 4.] [2. 3. 6.]] Обратная матрица к A: [[ 6. 9. -7.] [-2. -4. 3.] [-1. -1. 1.]] Произведение A на обратную должна быть единичной: [[1. 0. 0.] [0. 1. 0.] [0. 0. 1.]]
13. Собственные числа и собственные вектора матрицы
Напоминание теории. Для квадратных матриц определены понятия собственного вектора и собственного числа.
Пусть A — квадратная матрица и A ∈ ℝ n×n . Собственным вектором матрицы A называется такой ненулевой вектор x ∈ ℝ n , что для некоторого λ ∈ ℝ выполняется равенство Ax = λx . При этом λ называется собственным числом матрицы A . Собственные числа и собственные векторы матрицы играют важную роль в теории линейной алгебры и ее практических приложениях.
В NumPy собственные числа и собственные векторы матрицы вычисляются с помощью функции numpy.linalg.eig(a), где a — исходная матрица. В качестве результата эта функция выдает одномерный массив w собственных чисел и двумерный массив v, в котором по столбцам записаны собственные вектора, так что вектор v[:, i] соотвествует собственному числу w[i].
a = np.array([[-1, -6], [2, 6]]) w, v = np.linalg.eig(a)
print ("Матрица A:\n", a) print ("Собственные числа:\n", w) print ("Собственные векторы:\n", v)
Матрица A: [[-1 -6] [ 2 6]] Собственные числа: [2. 3.] Собственные векторы: [[-0.89442719 0.83205029] [ 0.4472136 -0.5547002 ]]
Обратите внимание: у вещественной матрицы собственные значения или собственные векторы могут быть комплексными.
14. Расстояния между векторами
Вспомним некоторые нормы, которые можно ввести в пространстве ℝ n , и рассмотрим, с помощью каких библиотек и функций их можно вычислять в NumPy.
p-норма
p-норма (норма Гёльдера) для вектора x = (x1, …, xn) ∈ ℝ n вычисляется по формуле:
‖ x ‖ p = ( n ∑ i = 1 | xi | p ) 1 ⁄ p , p ≥ 1.
В частных случаях при: * p = 1 получаем ℓ1 норму * p = 2 получаем ℓ2 норму
Далее нам понабится модуль numpy.linalg, реализующий некоторые приложения линейной алгебры. Для вычисления различных норм мы используем функцию numpy.linalg.norm(x, ord=None, . ), где x — исходный вектор, ord — параметр, определяющий норму (мы рассмотрим два варианта его значений — 1 и 2). Импортируем эту функцию:
from numpy.linalg import norm
ℓ1 норма
ℓ1 норма (также известная как манхэттенское расстояние) для вектора x = (x1, …, xn) ∈ ℝ n вычисляется по формуле:
‖ x ‖ 1 = n ∑ i = 1 | xi | .
Ей в функции numpy.linalg.norm(x, ord=None, . ) соответствует параметр ord=1.
a = np.array([1, 2, -3]) print('Вектор a:', a)
Вектор a: [ 1 2 -3]
print('L1 норма вектора a:\n', norm(a, ord=1))
L1 норма вектора a: 6.0
ℓ2 норма
ℓ2 норма (также известная как евклидова норма) для вектора x = (x1, …, xn) ∈ ℝ n вычисляется по формуле:
‖ x ‖ 2 = √ ( n ∑ i = 1 ( xi ) 2 ) .
Ей в функции numpy.linalg.norm(x, ord=None, . ) соответствует параметр ord=2.
print ('L2 норма вектора a:\n', norm(a, ord=2))
L2 норма вектора a: 3.7416573867739413
Более подробно о том, какие еще нормы (в том числе матричные) можно вычислить, см. документацию.
15. Расстояния между векторами
Для двух векторов x = (x1, …, xn) ∈ ℝ n и y = (y1, …, yn) ∈ ℝ n ℓ1 и ℓ2 раccтояния вычисляются по следующим формулам соответственно:
ρ1 ( x, y ) = ‖ x − y ‖ 1 = n ∑ i = 1 | xi − yi |
ρ2 ( x, y ) = ‖ x − y ‖ 2 = √ ( n ∑ i = 1 ( xi − yi ) 2 ) .
a = np.array([1, 2, -3]) b = np.array([-4, 3, 8]) print ('Вектор a:', a) print ('Вектор b:', b)
Вектор a: [ 1 2 -3] Вектор b: [-4 3 8]
print ('L1 расстояние между векторами a и b:\n', norm(a - b, ord=1)) print ('L2 расстояние между векторами a и b:\n', norm(a - b, ord=2))
L1 расстояние между векторами a и b: 17.0 L2 расстояние между векторами a и b: 12.12435565298214
16. Скалярное произведение и угол между векторами
a = np.array([0, 5, -1]) b = np.array([-4, 9, 3]) print ('Вектор a:', a) print ('Вектор b:', b)
Вектор a: [ 0 5 -1] Вектор b: [-4 9 3]
Скалярное произведение в пространстве ℝ n для двух векторов x = (x1, …, xn) и y = (y1, …, yn) определяется как:
⟨x, y⟩ = n ∑ i = 1 xiyi.
Длиной вектора x = (x1, …, xn) ∈ ℝ n называется квадратный корень из скалярного произведения, то есть длина равна евклидовой норме вектора:
| x | = √ ( ⟨x, x⟩ ) = √ ( n ∑ i = 1 x 2 i ) = ‖ x ‖ 2.
Теперь, когда мы знаем расстояние между двумя ненулевыми векторами и их длины, мы можем вычислить угол между ними через скалярное произведение:
⟨x, y⟩ = | x | |y|cos(α) ⟹ cos(α) = ( ⟨x, y⟩ )/( | x | |y| ) ,
где α ∈ [0, π] — угол между векторами x и y .
cos_angle = np.dot(a, b) / norm(a) / norm(b) print ('Косинус угла между a и b:', cos_angle) print ('Сам угол:', np.arccos(cos_angle))
Косинус угла между a и b: 0.8000362836474323 Сам угол: 0.6434406336093618
17. Комплексные числа в питоне
Напоминание теории. Комплексными числами называются числа вида x + iy , где x и y — вещественные числа, а i — мнимая единица (величина, для которой выполняется равенство i 2 = − 1 ). Множество всех комплексных чисел обозначается буквой ℂ (подробнее про комплексные числа см. википедию).
В питоне комплескные числа можно задать следующим образом (j обозначает мнимую единицу):
a = 3 + 2j b = 1j
print ("Комплексное число a:\n", a) print ("Комплексное число b:\n", b)
Комплексное число a: (3+2j) Комплексное число b: 1j
С комплексными числами в питоне можно производить базовые арифметические операции так же, как и с вещественными числами:
c = a * a d = a / (4 - 5j)
print ("Комплексное число c:\n", c) print ("Комплексное число d:\n", d)
Комплексное число c: (5+12j) Комплексное число d: (0.0487804878048781+0.5609756097560976j)
Задания: (Блок 2)
Задание 3:
Рассмотрим сложную математическую функцию на отрезке [1, 15]:
f(x) = sin(x / 5) * exp(x / 10) + 5 * exp(-x / 2)
Она может описывать, например, зависимость оценок, которые выставляют определенному сорту вина эксперты, в зависимости от возраста этого вина. Мы хотим приблизить сложную зависимость с помощью функции из определенного семейства. В этом задании мы будем приближать указанную функцию с помощью многочленов.
Как известно, многочлен степени n (то есть w0 + w1x + w2x 2 + … + wnx n ) однозначно определяется любыми n + 1 различными точками, через которые он проходит. Это значит, что его коэффициенты w0 , … wn можно определить из следующей системы линейных уравнений:
где через x1, . xn, xn + 1 обозначены точки, через которые проходит многочлен, а через f(x1), . f(xn), f(xn + 1) — значения, которые он должен принимать в этих точках.
Воспользуемся описанным свойством, и будем находить приближение функции многочленом, решая систему линейных уравнений.
- Сформируйте систему линейных уравнений (то есть задайте матрицу коэффициентов A и свободный вектор b) для многочлена первой степени, который должен совпадать с функцией f в точках 1 и 15. Решите данную систему с помощью функции scipy.linalg.solve. Нарисуйте функцию f и полученный многочлен. Хорошо ли он приближает исходную функцию?
- Повторите те же шаги для многочлена второй степени, который совпадает с функцией f в точках 1, 8 и 15. Улучшилось ли качество аппроксимации?
- Повторите те же шаги для многочлена третьей степени, который совпадает с функцией f в точках 1, 4, 10 и 15. Хорошо ли он аппроксимирует функцию? Коэффициенты данного многочлена (четыре числа в следующем порядке: w_0, w_1, w_2, w_3) являются ответом на задачу. Округлять коэффициенты не обязательно, но при желании можете произвести округление до второго знака (т.е. до числа вида 0.42)
Сайт построен с использованием Pelican. За основу оформления взята тема от Smashing Magazine. Исходные тексты программ, приведённые на этом сайте, распространяются под лицензией GPLv3, все остальные материалы сайта распространяются под лицензией CC-BY.
Установка и первое знакомство
Язык Python стал популярен благодаря своей богатой библиотеке. Я его воспринимаю как некоего начальника, который через свои команды раздает задачи подчиненным. Они выполняются и на выходе получается некий результат работы программы:
Из всех известных мне языков высокого уровня, этот, наверное, самый высокий, а потому, один из самых удобных в реализации алгоритмов. Но чтобы им успешно пользоваться нужно уметь раздавать приказы подчиненным. И в этой серии занятий мы познакомимся с еще одним исполнителем языка Python – пакетом NumPy.
Вообще, NumPy предназначен для выполнения научных вычислений и активно используется не только в качестве самостоятельной библиотеки учеными и преподавателями по всему миру, но и входит в состав многих других популярных пакетов. С одним из них – Keras, мы с вами недавно познакомились, когда изучали основы работы НС. И вы могли заметить, что вначале программ фигурировала строчка:
import numpy as np
Это, как раз, выполнение импорта того самого пакета NumPy.
Но почему он стал так популярен? Причин несколько. Самое главное, критичные по скорости вычисления фрагменты реализованы на языках Си и Фортран. Также он имеет довольно простой и продуманный синтаксис, а, значит, им легко пользоваться. Ну и, наконец, богатство возможностей этой библиотеки, начиная с базовых математических функций и заканчивая работой с полиномами, линейной алгеброй и многомерными матрицами (тензорами). Все это очень часто используется в инженерных задачах, отсюда и высокая популярность пакета.
Установка NumPy
Я думаю, вы прониклись уважением к этому пакету, и пришла пора прикоснуться к «святому граалю». В начале, как всегда, его нужно установить. Сделать это чрезвычайно просто, достаточно выполнить в терминале команду:
pip install numpy
Не удивляйтесь, если этот пакет у вас уже установлен, так как он входит в состав многих других библиотек. Проверить установку можно командой:
import numpy as np
Если такая программа выполняется без ошибок, то этот «святой грааль» уже присутствует на вашем устройстве и готов к истязаниям.
У вас здесь уже может возникнуть вопрос: почему импорт записан в таком виде? А не просто: import numpy? Можно и так, но тогда в программе все время придется использовать префикс numpy. Гораздо удобнее писать две буквы «np». Поэтому общепринятой практикой стало импортирование этого пакета именно в таком виде. Я буду следовать сложившейся традиции и делать также.
Фундаментальный элемент NumPy – массив (array)
Отлично, сложнейший этап установки и импорта пакета позади. Пришло время сделать первые шаги и вначале познакомиться с его фундаментальным элементом – однородным многомерным массивом. В NumPy элементы массива имеют единый тип данных. Их индексы описываются кортежем целых неотрицательных чисел. Размерность кортежа – это ранг массива (то есть, размерность массива), а каждое число в кортеже представляет свою отдельную ось:
Как создать массив в NumPy? Существует много способов, но базовый реализуется через функцию:
Здесь в качестве первого параметра object может выступать список или кортеж, а также функция или объект, возвращающий список или кортеж. Второй параметр dtype – это тип элементов массива. Если указано значение None, то тип будет определяться автоматически на основе переданных данных. Подробнее об этой функции можно, как всегда, почитать на странице официальной документации:
Итак, в самом простом варианте можно создать одномерный массив так:
a = np.array([1, 2, 3, 4])
В результате получим объект типа array с элементами 1, 2, 3, 4:
Какой будет тип у этих элементов? Мы можем его посмотреть с помощью атрибута dtype, выполнив в консоли строчку:
a.dtype
То есть, автоматически был применен целочисленный тип размерностью 32 бит. Ну, хорошо, а что если попробовать создать массив с разными типами его элементов, например, так:
a = np.array([1, 2, "3", True])
В результате увидим, следующее содержимое:
Все элементы стали строкового типа. Этот пример показывает, что в массивах NumPy используется единый тип данных его элементов: или все целочисленные, или строковые, или вещественные и так далее. Смешение типов в рамках одного массива не допускается.
Отлично, это мы сделали. Как теперь можно обращаться к отдельным элементам массива? Для этого используется общий синтаксис:
Например, для нашего одномерного случая, мы можем взять первый элемент из массива a, следующим образом:
Увидим значение ‘1’. Обратите внимание, первый элемент имеет индекс 0, а не 1. Единица – это уже второй элемент:
a[1] # возвращает 2-й элемент со значением ‘2’
Для изменения значения элемента, достаточно присвоить ему новое значение, например:
a[1] = '123'
в результате получим массив:
А что будет, если мы попробуем присвоить значение другого типа данных, например, число:
a[1] = 234
Ошибки не будет, а значение автоматически будет преобразовано в строку:
Разработчики пакета NumPy постарались сделать его максимально дружественным, чтобы инженер сосредотачивался именно на решении задачи, а не на нюансах программирования. Поэтому везде, там где это допустимо, пакет NumPy берет на себя разрешение подобных нюансов. И, как показала практика, это очень удобно и заметно облегчает жизнь нам, простым смертным.
Минутка восхищения или что такого в массивах NumPy
Но, все-таки, что такого в массивах NumPy, что они повсеместно используются в разных библиотеках? Давайте я приведу несколько примеров, и вы сами все увидите.
Предположим, мы определили одномерный массив с числами от 1 до 9:
a = np.array([1,2,3,4,5,6,7,8,9])
Мы уже знаем как взять один отдельный элемент, но что будет, если прописать индексы для всех 9 элементов:
a[ [1,1,1,1,1,1,1,1,1] ]
На выходе увидим одномерный массив из двоек:
array([2, 2, 2, 2, 2, 2, 2, 2, 2])
a[ [1,1,1,1,1] ]
тогда получим аналогичный массив, но размерностью 5 элементов:
Как видите, индексирование здесь более гибкое, чем у обычных списков Python. Или, вот еще один характерный пример:
a[ [True, True, False, False, False, False, True, True, True] ]
Результат будет следующим:
То есть, остаются элементы со значениями True и отбрасываются со значениями False. Обо всем этом мы еще будем подробно говорить.
Еще один пример. Предположим, нам понадобилось представить одномерный массив a в виде матрицы 3х3. Нет ничего проще, меняем его размерность:
b = a.reshape(3, 3)
и получаем заветный результат:
Далее, можем обращаться к элементам матрицы b так:
b[1, 2]
В обоих случаях будет взят один и тот же элемент со значением 6.
Все это лишь мимолетный взгляд на возможности пакета NumPy. Я здесь лишь хотел показать, насколько сильно отличаются массивы array от списков языка Python, и если вы хотите овладеть этим инструментом, то эта серия занятий для вас.
Видео по теме
#1. Пакет numpy - установка и первое знакомство | NumPy уроки
#2. Основные типы данных. Создание массивов функцией array() | NumPy уроки
#3. Функции автозаполнения, создания матриц и числовых диапазонов | NumPy уроки
#4. Свойства и представления массивов, создание их копий | NumPy уроки
#5. Изменение формы массивов, добавление и удаление осей | NumPy уроки
#6. Объединение и разделение массивов | NumPy уроки
#7. Индексация, срезы, итерирование массивов | NumPy уроки
#8. Базовые математические операции над массивами | NumPy уроки
#9. Булевы операции и функции, значения inf и nan | NumPy уроки
#10. Базовые математические функции | NumPy уроки
#11. Произведение матриц и векторов, элементы линейной алгебры | NumPy уроки
#12. Множества (unique) и операции над ними | NumPy уроки
#13. Транслирование массивов | NumPy уроки
© 2023 Частичное или полное копирование информации с данного сайта для распространения на других ресурсах, в том числе и бумажных, строго запрещено. Все тексты и изображения являются собственностью сайта