Функции автозаполнения, создания матриц и числовых диапазонов

На предыдущем занятии мы познакомились с функцией array для создания произвольных массивов на основе переданного ей списка или кортежа. Однако, часто в инженерных задачах требуется определять векторы или матрицы с типовым набором значений, например, состоящих из нулей или единиц, или определение диагональной и единичной матриц и так далее. Конечно, мы можем все это сделать также через функцию array, используя механизм генерации списков, например, так:

np.array( [0]*10 )  # массив из 10 нулей
np.array( [1]*15 )  # массив из 15 единиц
np.array( [x for x in range(10)] ) # массив из чисел от 0  до 9

Но есть более быстрые способы (по скорости выполнения) создания подобных массивов. Для этого в NumPyимеются полезные функции, которые мы сейчас рассмотрим.

Функции автозаполнения элементов массива

Название

Описание

empty(shape, …)

Возвращает новый массив заданного размера и типа данных, но без определенных значений.

eye(N, M=None, …)

Возвращает массив размером NxMс единичными диагональными элементами (остальные элементы равны нулю).

identity(n, …)

Возвращает квадратный массив размерностью nxn с единичными элементами по главной диагонали (остальные равны нулю).

ones(shape, …)

Возвращает массив заданного размера и типа, состоящего из всех единиц.

zeros(shape, …)

Возвращает массив заданного размера и типа, состоящего из всех нулей.

full(shape, value, …)

Возвращает массив заданного размера и типа со значениями value.

Это только часть основных функций для создания массивов с заданными значениями. Использовать их достаточно просто. Например, так:

np.empty(10) # создание одномерного массива с произвольными числами
np.empty(10, dtype='int16')
np.empty((3, 2), dtype='float32') # возвращаетматрицу 3x2 стипомfloat32

Для функций eye и identity размерности указываются отдельными параметрами:

np.eye(4)    # матрица 4х4
np.eye(4, 2)         # матрица 4x2
np.identity(5) # матрица 5x5

Функции ones, zeros и full работают по аналогии с функцией empty:

np.zeros( (2, 3, 4) ) # нулевая матрица размерностью 2x3x4
np.ones( [4, 3], dtype='int8') # матрица 4x3 из единиц и типом int8
np.full((3, 2), -1) # матрица 3x2, состоящая из -1

Все эти функции работают быстрее, чем функция array с генератором списков языка Python. Поэтому их предпочтительно использовать при создании и инициализации массивов определенными значениями.

Функции создания матриц

Следующий полезный набор функций позволяет генерировать матрицы на основе списков или по определенным правилам.

Название

Описание

mat(object, …)

Приводит входные данные object к матрице, если это возможно. Параметр object может быть строкой, списком или кортежем.

diag(list, …)

Формирует диагональную матрицу на основе списка или массива NumPy. В последних версиях возвращает копию массива (а не его представление).

diagflat(list, …)

Формирует диагональную матрицу из списка list, который сначала сжимает до одной оси (преобразует в одномерный список или массив).

tri(N, M=None, …)

Создает треугольный массив NxM с единицами на главной диагонали и ниже ее.

tril(list, …)

Преобразует двумерный список или массив list в треугольную матрицу с нулевыми элементами выше главной диагонали.

triu(list, …)

Преобразует двумерный список или массив list в треугольную матрицу с нулевыми элементами ниже главной диагонали.

vander(list, N=None, …)

Создание матрицы Вандермонда из одномерного списка или массива list. Второй параметр N определяет число столбцов (по умолчанию формируется квадратная матрица).

Давайте посмотрим как работают эти функции.

np.mat('1 2 3 4') # создает матрицу 1x4 из строки
np.mat('1, 2, 3, 4') # то же самое: создает матрицу 1x4 из строки
np.mat('1 2; 3 4') # возвращает матрицу 2x2

Или же, вместо строк можно использовать список или кортеж:

np.mat([5, 4, 3])
np.mat( [(1,2,3), (4,5,6)])

Но, если из переданных данных нельзя сформировать прямоугольную таблицу (матрицу), то произойдет ошибка:

np.mat( [(1,2,3), (4,5,6,7)])# ошибка, размерности не совпадают

Следующая функция позволяет формировать диагональные матрицы:

np.diag([1, 2, 3]) # диагональная матрица 3x3

Но, если ей передать двумерный список, то она возвратит одномерный массив из элементов, стоящих на главной диагонали:

np.diag([(1,2,3), (4,5,6), (7,8,9)]) # выделение элементов главной диагонали

Если же мы хотим сформировать диагональную матрицу из многомерных списков или массивов, то следует воспользоваться функцией

np.diagflat([(1,2,3), (4,5,6), (7,8,9)])

Следующий набор функций используются для формирования треугольных матриц. Например:

np.tri(4) # треугольная матрица 4x4
np.tri(4, 2) # треугольная матрица 4x2

Если нужно привести уже существующие матрицы к треугольному виду, то это можно сделать так:

a = np.array( [(1,2,3), (4,5,6), (7,8,9)] )
np.tril(a) # нижняя треугольная матрица размером 3x3
np.triu(a) # верхняя треугольная матрица размером 3x3

Если указать одномерный список:

np.tril([1,2,3])

то будет создана треугольная матрица 3x3 из строк [1, 2, 3].

Также функции tril и triu будут работать и с многомерными массивами:

np.tril([[[1,2,3], [4,5,6], [7,8,9]]])
np.tril([[[1,2,3], [4,5,6], [7,8,9]], [[10,20,30], [40,50,60], [70,80,90]], [[100,200,300], [400,500,600], [700,800,900]]])

В этом случае последние двумерные сечения будут приведены к треугольному виду.

Последняя функция этойгруппы формирует матрицу Вандермонда из одномерных списков или массивов:

np.vander([1,2,3]) # матрица Вандермонда 3x3

Функции формирования числовых диапазонов

Следующая группа функций, которые мы рассмотрим на этом занятии, служит для формирования числовых диапазонов. Что делают эти функции? Когда мы с вами изучали язык Python, то говорили о функции

range(Start, Stop, Step)

которая генерирует числовой диапазон с параметрами Start, Stop, Step. Причем, все эти параметры должны быть целочисленными. В NumPy есть подобные функции, но более гибкие и работающие с вещественными величинами.

Название

Описание

arange()

Возвращает одномерный массив с равномерно разнесенными числами указанного диапазона.

linspace(start, stop, …)

Возвращает одномерный массивcравномерно разнесенными числами, используя только значения начала и конца интервала.

logspace(start, stop, …)

Возвращает одномерный массив с числами, равномерно распределенных по логарифмической шкале.

geomspace(start, stop, …)

Формирование чисел по геометрической прогрессии.

meshgrid(x1, ..., xn, …)

x1, ..., xn – одномерные последовательности или массивы, используемые для формирования координатной сетки по каждой из осей.

mgrid[]

Возвращает массив плотных координатных сеток.

ogrid[]

Возвращает открытую сетку значений.

Давайте рассмотрим некоторые из них. Первая функция arrange довольно часто применяется в программах на Python. Она позволяет проходить заданный интервал с указанным шагом, например, так:

np.arange(5)# интервал [0; 5) с шагом 1
np.arange(1, 5)# интервал [1; 5) с шагом 1
np.arange(1, 5, 0.5) # интервал [1; 5) с шагом 0,5

Обратите внимание, в отличие от функции range языка Python в arrange пакета NumPy можно указывать вещественные значения. Вот еще один пример, демонстрирующий это:

np.arange(0, np.pi, 0.1)

Здесь все величины вещественные. Мы начинаем движение от значения 0 с шагом 0,1 пока не дойдем до значения пи (не включая его). И, далее, используя этот массив, можно вычислить синус или косинус от всех этих значений:

np.cos(np.arange(0, np.pi, 0.1))

Видите, как это удобно. Без пакета NumPyнам пришлось бы писать цикл и делать вычисление для каждого значения аргумента. А здесь мы сразу получаем готовый массив значений функции косинуса. Это работает гораздо быстрее циклов в Python.

Похожим образом работает и функция linspace. Она разбивает указанный интервал на равномерные отрезки и возвращает массив этих значений:

Мы указываем в качестве аргументов интервал [start; stop] и число отметок в этом интервале n. Если n = 0, то получим пустой массив. При n = 1 – значение start. При n = 2 – значения start и stop. При n> 2 равномерное разбиение интервала точками m = n-2. Например:

np.linspace(0, np.pi, 0) # пустой массив
np.linspace(0, np.pi, 1) # одно значение 0
np.linspace(0, np.pi, 2) # два значения: 0 и pi
np.linspace(0, np.pi, 3) # три значения: 0, pi/2, pi

В чем отличие linspace от arange? В arange мы указываем сами шаг движения по числовой оси. При этом число значений определяется граничными значениями. А в linspace мы задаем граничные значения и число делений, а шаг вычисляется автоматически.

Функции logspace и geomspace работают аналогичным образом. У них указываются граничные значения и число членов, а на выходе имеем массив из соответствующих величин. Например:

np.logspace(0, 1, 3) # значения: 1, sqrt(10), 10
np.logspace(0, 1, 4) # значения: 1, 2.15, 4.64, 10
 
np.geomspace(1, 4, 3) # значения: 1, 2, 4
np.geomspace(1, 16, 5) # значения: 1, 2, 4, 8, 16

Остальные функции этой группы используются при построении графиков и мы их рассмотрим, когда будем рассматривать построение графиков с помощью библиотеки matplotlib.

Функции формирования массивов на основе данных

Рассмотрим следующую группу, связанную с формированием на основе уже имеющихся данных.

Название

Описание

array(object, …)

Преобразует список или кортеж object в массив NumPy.

asanyarray(list, …)

Преобразует список list в массив array, сохраняя тип подкласса.

ascontiguousarray(list, …)

Возвращает непрерывный массив в памяти, подобно как это организовано в языке C.

asmatrix(list, …)

Преобразует входную последовательность list в матрицу NumPy (тип matrix).

copy(list, …)

Возвращает копию массива list (если это объект NumPy) или просто создает массив на основе списка языка Python.

frombuffer(buffer, …)

Преобразует данные из буфера в массив NumPy

fromfile(file, …)

Возвращает массив из данных текстового или бинарного файла file.

fromfunction(func, shape, …)

Создает массивразмерностью shape с помощью функции func.

fromiter(iter, …)

Создает массив на основе итерируемого объекта.

fromstring(string, …)

Создает массив из данных строки.

loadtxt(file, …)

Формирует массив из данных текстового файла.

Работа этих функций вполне очевидна, рассмотрим только некоторые из них. Функция copy выполняет копирование массива. Например, имеется массив:

a = np.array( [(1, 2), (3, 4)] )

И создать его копию в памяти устройства, можно так:

b = np.copy(a)

В этом легко убедиться, если вывести id этих объектов:

print(id(a), id(b))

Формирование массива с помощью функции выполняется следующим образом:

def getRange(x, y):
    return 100*x + y
 
a = np.fromfunction(getRange, (2, 2))
print(a)

Обратите внимание, функция принимает два аргумента, т.к. формируется двумерная матрица размерами 2x2. То есть, число аргументов функции равно размерности матрицы и каждый аргумент соответствует индексу по своей оси. При выполнении этой программы в консоли увидим результат:

[[  0.   1.]
 [100. 101.]]

Отсюда хорошо видно как менялись значения x, y при формировании матрицы. При формировании первой строки x = 0, а yменялся от 0 до 1, при формировании второй строки: x = 1, yот 0 до 1.

Часто совместно с fromfunction используют лямбда-функции в виде:

np.fromfunction(lambda x, y: x*100+y, (2, 2))

Результат будет тем же.

Следующая функция fromiter позволяет формировать массив на основе любого итерируемого объекта. Например:

np.fromiter("hello", dtype='U1')

Здесь строка воспринимается как итерируемый объект и разбивается по символам. Или, можносделатьтак:

def getRange(N):
    for i in range(N):
        yield i
 
a = np.fromiter(getRange(4), dtype='int8')
print(a)

Здесь в качестве объекта передается функция-генератор и на выходе получаем одномерный массив чисел:

[0 1 2 3]

Последняя функция, которую мы рассмотрим fromstring позволяет создавать массив из строковых данных, например, так:

np.fromstring('1 2 3', dtype='int16', sep= ' ')

Здесь параметр sep определяет разделитель между данными. Если числа следуют через запятую, то это явно нужно указать в разделителе:

np.fromstring('1, 2, 3', dtype='int16', sep= ',')

Это не все функции, с помощью которых можно формировать массивы в NumPy. Я отметил лишь наиболее употребительные. Полный их список и подробное описание можно посмотреть на официальном сайте:

https://numpy.org/doc/stable/