Создание массивов#

Импортируем NumPy и начинаем работу:

import numpy as np

Преобразование в массив из стандартных коллекций Python (list, tuple и ряда других) осуществляется функцией np.array.

Одномерный массив:

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

Двумерный массив:

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

Трёхмерный массив:

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

       [[5, 6],
        [7, 8]]])

Можно явно указать тип чисел (данных) массива. Делается это с помощью указания параметра dtype:

np.array([1, 2, 3], dtype=float)
array([1., 2., 3.])

Для создания одномерных массивов в NumPy имеются такие функции, как np.linspace и np.arange.

Функция np.arange создаёт массив по заданным началу, концу и шагу - np.arange(start, stop, step):

# Указан только конец интервала stop
# Начало по умолчанию принято за 0
np.arange(10)
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
# start, stop
np.arange(2, 10)
array([2, 3, 4, 5, 6, 7, 8, 9])
# start, stop, step
np.arange(2, 10, 2)
array([2, 4, 6, 8])
# массив float (т.к. шаг имеет тип float)
np.arange(2, 3, 0.1)
array([2. , 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9])

Warning

По умолчанию конец интервала (3 в последнем случае) не входит в итоговый массив. Так получается, как правило, из-за ошибок округления компьютером вещественных чисел. Всегда стоит об этом помнить.

Функция np.linspace создаёт массив по заданным началу, концу и числу точек, равномерно расположенных от начального до конечного значения:

# start, stop, num
np.linspace(1, 4, 6)
array([1. , 1.6, 2.2, 2.8, 3.4, 4. ])

Note

При использовании np.linspace в отличие от np.arange последнее значение всегда входит в созданный массив.

Для создания двумерных массивов имеются следующие функции: np.eye, np.diag и np.vander.

Функция np.eye инициализирует единичную матрицу. В общем случае можно сгенерировать и прямоугольную матрицу \(\mathbf{A}\), у которой все элементы равны нулю, кроме единиц, стоящих в псевдодиагонали, где индекс строки \(i\) совпадает с индексом столбца \(j\), то есть \(a_{i j} = 1\) при \(i = j\) и \(a_{i j} = 0\) при \(i \neq j\).

# Единичная матрица 3x3
np.eye(3)
array([[1., 0., 0.],
       [0., 1., 0.],
       [0., 0., 1.]])

Обратите внимание, что тип данных по умолчанию float. Иной тип данных необходимо указывать явно.

# То же, но целочисленный вариант
np.eye(3, dtype=int)
array([[1, 0, 0],
       [0, 1, 0],
       [0, 0, 1]])
# Прямоугольный вариант
np.eye(3, 5)
array([[1., 0., 0., 0., 0.],
       [0., 1., 0., 0., 0.],
       [0., 0., 1., 0., 0.]])

Функция np.diag по переданному одномерному массиву (списку, кортежу) создаёт диагональную матрицу, на диагонали которой расположены элементы переданного массива:

np.diag([1, 2, 3])
array([[1, 0, 0],
       [0, 2, 0],
       [0, 0, 3]])

Здесь тип данных по умолчанию определяется по типу переданных данных. В данном случае был передан список целых чисел (int). Можно указать тип данных и вручную через dtype=....

# С указанием смещения от главной диагонали
np.diag([1, 2, 3], 1)
array([[0, 1, 0, 0],
       [0, 0, 2, 0],
       [0, 0, 0, 3],
       [0, 0, 0, 0]])

np.diag не только создаёт квадратную матрицу с диагональными элементами, но может и выделять диагональные элементы из заданной матрицы.

# Получение диагонали матрицы
a = np.array([(1, 2), (3, 4)])
np.diag(a)
array([1, 4])

Функция np.vander несколько специфична - она создаёт матрицу Вандермонда. С помощью этой функции по переданному массиву a длины \(m\) создаётся матрица с \(n\) столбцами, каждый столбец которой является переданным массивом a, каждый элемент которого возведён в степень \(n - j - 1\), где \(j\) - индекс столбца:

# (a, n)
np.vander([1, 2, 3, 4], 2)
array([[1, 1],
       [2, 1],
       [3, 1],
       [4, 1]])
# Первый столбец - кубы элементов массива
# Второй - квадраты и т.д.
np.vander([1, 2, 3, 4], 4)
array([[ 1,  1,  1,  1],
       [ 8,  4,  2,  1],
       [27,  9,  3,  1],
       [64, 16,  4,  1]])

Для создания массивов произвольной размера (формы, shape) применяются функции np.zeros, np.ones, np.full и random.

Note

О генераторах случайных чисел, в т.ч. в NumPy, см. Использование генераторов псевдослучайных чисел.

Функция np.zeros создаёт массив заданной формы, заполненный нулями.

Note

Тип данных по умолчанию - float.

# Одномерный массив
np.zeros(3)
array([0., 0., 0.])
# Двумерный массив
# (обратите внимание, что форма передаётся как кортеж,
# список или массив, а не просто через запятую)
np.zeros((3, 5))
array([[0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0.]])
# То же, но целочисленный вариант
np.zeros((3, 5), dtype=int)
array([[0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0]])
# Трёхмерный массив
np.zeros((2, 3, 5))
array([[[0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0.]],

       [[0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0.]]])

Функция np.ones устроена тем же образом и делает то же самое, но заполняет массив единицами:

np.ones((2, 3))
array([[1., 1., 1.],
       [1., 1., 1.]])

Функция np.full возвращает массив заданной формы, заполненный заданным значением. Тип данных определяется типом переданного значения либо указывается явно.

# (форма, значение)
np.full((2, 3), 3.5)
array([[3.5, 3.5, 3.5],
       [3.5, 3.5, 3.5]])
np.full(3, -1)
array([-1, -1, -1])

Чтобы сгенерировать массив, заполненный псевдослучайными числами используется генератор таких чисел. Стандартный NumPy-генератор псевдослучайных чисел создаётся просто:

rg = np.random.default_rng()

С помощью этого генератора возможно создавать различные массивы (подробнее в Использование генераторов псевдослучайных чисел):

# Матрица, заполненная случайными числами от 0 до 1
rg.random((5, 3))
array([[0.83350103, 0.25405848, 0.83745866],
       [0.46880512, 0.13421931, 0.13031926],
       [0.45732792, 0.6692817 , 0.32947936],
       [0.21377765, 0.0461932 , 0.54430177],
       [0.20746495, 0.492854  , 0.45904645]])

NumPy также имеет функцию создания массива индексов np.indices. Создаваемый ею массив индексов полезен для операций с массивами на регулярной сетке.

np.indices((3, 3))
array([[[0, 0, 0],
        [1, 1, 1],
        [2, 2, 2]],

       [[0, 1, 2],
        [0, 1, 2],
        [0, 1, 2]]])

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

np.fromiter((x for x in range(1, 10, 2)), int)
array([1, 3, 5, 7, 9])

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

Создавать массив, используя обычную Python-функцию, позволяет функция np.fromfunction:

# (создающая функция, форма массива)
np.fromfunction(lambda i, j: i, (2, 2))
array([[0., 0.],
       [1., 1.]])
np.fromfunction(lambda i, j: j, (2, 2))
array([[0., 1.],
       [0., 1.]])
np.fromfunction(lambda i, j: i + j, (3, 3), dtype=int)
array([[0, 1, 2],
       [1, 2, 3],
       [2, 3, 4]])
def gen_array(i, j):
    return i * j

np.fromfunction(gen_array, (3, 3), dtype=int)
array([[0, 0, 0],
       [0, 1, 2],
       [0, 2, 4]])

Создание подобных массивов#

Рассмотренные выше функции np.zeros, np.ones и np.full имеют близкие по результату функции np.zeros_like, np.ones_like и np.full_like. Новые функции на вход принимают не форму нового массива, а другой массив, из которого берут и форму, и тип данных.

# Пусть есть массив со случайными целыми числами
a = rg.integers(-10, 11, size=(3, 5))
a
array([[-6,  1, -4, -5, -6],
       [ 8,  5,  6,  4,  4],
       [ 5,  5, -4, -7, -1]])

Тогда мы можем создать подобные ему массивы.

np.zeros_like(a)
array([[0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0]])
# Скопируем массив
b = a.copy()
# И у нового изменим тип данных на float
b.dtype = float
# Как следствие, изменится и тип данных подобного массива
np.ones_like(b)
array([[1., 1., 1., 1., 1.],
       [1., 1., 1., 1., 1.],
       [1., 1., 1., 1., 1.]])
np.full_like(a, 77)
array([[77, 77, 77, 77, 77],
       [77, 77, 77, 77, 77],
       [77, 77, 77, 77, 77]])
np.full_like(a, 0.1)
array([[0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0]])

Заметьте, вместо массива, заполненного 0.1, получили массив нулей. Это случилось потому, что тип данных в исходном массиве a есть int. Соответственно, дробная часть у 0.1 была отброшена.

Автоматически тип данных подобного массива не изменяется, а назначается таким же, как у исходного массива. Изменить это можно, явно указав тип данных:

np.full_like(a, 0.1, dtype=float)
array([[0.1, 0.1, 0.1, 0.1, 0.1],
       [0.1, 0.1, 0.1, 0.1, 0.1],
       [0.1, 0.1, 0.1, 0.1, 0.1]])

Создание массивов из файлов#

NumPy имеет средства для чтения данных из файлов стандартных (для NumPy) и произвольных форматов.

Для чтения данных из текстового файла (текстовым является не только .txt файл) используется функция np.loadtxt.

Пусть есть CSV-файл simple.csv со следующим содержимым:

x,y
0,0
1,1
2,4
3,9

Создать NumPy-массив на его основе несложно:

# Прочитать заданный файл,
# разделителем значений считать запятую,
# не читать первую строку файла (заголовок CSV)
np.loadtxt(
    "simple.csv",
    delimiter=",",
    skiprows=1
)
array([[0., 0.],
       [1., 1.],
       [2., 4.],
       [3., 9.]])

См. также#

  1. Более подробная информация на официальном сайте NumPy.

  2. Подробная информация о чтении и записи файлов в NumPy.

  3. Использование генераторов псевдослучайных чисел.