Заполнение массивов в NumPy с помощью функций. Типы данных

Создано: 17.11.2025

В данном уроке будут рассмотрены функции array, arange, linspace, zeros, ones и empty библиотеки NumPy, с помощью которых создаются экземпляры ndarray (массивы) и происходит их заполнение определенными значениями. Заполнение случайными числами будет изучаться позже, как и создание двумерных и многомерных массивов. Вместо этого здесь уделим внимание типам данных элементов, которыми заполняются массивы NumPy.

Создание одномерных массивов и их заполнение заданными значениями

Самым очевидным способом создания массива является вызов функции array() и передача ей любой последовательности Python с явно заданными значениями элементов:

import numpy as np

a = np.array([10.55, 12.78, 3, -4, 5.1])
b = np.array(('hello', 'world', 'ocean', 'planet'))
c = np.array(range(100, 120, 3))

print(a, type(a))
print(b, type(b))
print(c, type(c))
[10.55 12.78  3.   -4.    5.1 ] <class 'numpy.ndarray'>
['hello' 'world' 'ocean' 'planet'] <class 'numpy.ndarray'>
[100 103 106 109 112 115 118] <class 'numpy.ndarray'>

Так в примере выше в array() передается список, кортеж и объект range, и независимо ни от этого, ни от типов содержащихся в них данных всегда создаются экземпляры ndarray — массивы NumPy. Функция не принимает "голые значения" за исключением случая, когда передается только одно:

a = np.array(1024)
print(a, type(a))
1024 <class 'numpy.ndarray'>

Тогда создается массив с так называемой нулевой размерностью (даже не одномерный).

В первом примере мы передаем в функцию array() библиотеки NumPy экземпляр, созданный встроенной функцией range() языка Python. Однако делать так нет необходимости, поскольку в самом NumPy есть функция arange, которая вызывается вместо array(). Она также возвращает экземпляр ndarray, заполненный согласно переданному в нее диапазону.

a = np.arange(10)
b = np.arange(-5, 3)
c = np.arange(10, 1, -1)
d = np.arange(0.5, 3)
e = np.arange(0.54, 1.7, 0.21)

print(f'{a}\n{b}\n{c}\n{d}\n{e}')
[0 1 2 3 4 5 6 7 8 9]
[-5 -4 -3 -2 -1  0  1  2]
[10  9  8  7  6  5  4  3  2]
[0.5 1.5 2.5]
[0.54 0.75 0.96 1.17 1.38 1.59]

В отличие от range() в arange() можно передавать вещественные числа. Но это не очень удобно, так как трудно понять сколько всего будет значений в массиве. Когда нужно точно задать количество элементов, вместо arange лучше подходит linspace. Однако здесь уже не задается шаг, разница между соседними значениями вычисляется, исходя из количества элементов и диапазона. Можно сказать, отрезок нарезается на равные части.

a = np.linspace(-6, 7, 4)
b = np.linspace(0.1, 1.7, 5)

print(a)
print(b)
[-6.         -1.66666667  2.66666667  7.        ]
[0.1 0.5 0.9 1.3 1.7]

Обратим внимание, что в случае linspace верхняя граница входит в диапазон, что логично.

Если массив надо заполнить только нулями или только единицами, то это делается вызовом функций zeros() или ones().

a = np.zeros(10)
b = np.ones(10)

print(a)
print(b)
[0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]

Точки в выводе выше — это не разделители между элементами, а указание на дробность чисел. Как заполнить массив другими типами данных, будет сказано ниже.

Наконец, остановимся на функции empty. Она создает массив заданной размерности, но ничем его не заполняет. Однако в занятых под массив ячейках памяти уже содержатся те или иные значения (могут и нули), поэтому массив оказывается не столько пустым, сколько заполненным "мусором".

a = np.empty(3)
print(a)
[6.70315468e-310 2.91923454e-315 6.70315297e-310]

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

Типы данных NumPy

Отличие истинных массивов от списков Python заключается не только в скорости их обработки (с массивами это происходит куда быстрее). Также важно, что количество элементов в массиве должно оставаться постоянным, а все значения быть одного типа.

Если мы извлечем отдельный элемент (в случае с одномерными массивами делается это также как со списками) и посмотрим его тип, то несколько удивимся:

a = np.array([10.55, 12.78, 3, -4, 5.1])
print(a[0], type(a[0]))
print(a[-2], type(a[-2]))
10.55 <class 'numpy.float64'>
-4.0 <class 'numpy.float64'>

Вместо типа float языка Python в NumPy используется тип float64. Кроме того, из примера видно, что целое число -4 было преобразовано в этот тип. Если бы был задан смешанный список чисел и строк, то все значения были бы преобразованы в строку. Чтобы получить массив целых чисел, все входные значения должны быть таковыми.

a = np.array([10, 'hello', 3, -4, 5])
b = np.array([10, 12, 3, -4, 5])
print(a, type(a[0]))
print(b, type(b[0]))
['10' 'hello' '3' '-4' '5'] <class 'numpy.str_'>
[10 12  3 -4  5] <class 'numpy.int64'>

У экземпляров ndarray есть свойство dtype, позволяющее посмотреть тип данных составляющих массив элементов:

a = np.arange(1, 5)
b = np.linspace(0, 2, 6)
c = np.array(['yes', 'no'])
d = np.array(['Moscow', 'New York'])
e = np.array(['правда', 'ложь'])
print(a, a.dtype)
print(b, b.dtype)
print(c, c.dtype)
print(d, d.dtype)
print(e, e.dtype)
[1 2 3 4] int64
[0.  0.4 0.8 1.2 1.6 2. ] float64
['yes' 'no'] <U3
['Moscow' 'New York'] <U8
['правда' 'ложь'] <U6

Как мы видим, строковый тип данных конкретизируется: показывается, сколько символов юникод отводится под каждый элемент. Размер определяется самой длинной строкой.

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

a = np.arange(1, 50, 15, dtype='i2')
b = np.linspace(1, 50, 6, dtype=int)
c = np.linspace(1, 50, 6, dtype='f4')
d = np.linspace(1, 50, 6, dtype=float)
e = np.array(['правда', 'ложь'], dtype='U10')
f = np.ones(5, dtype='i1')

print(a, a.dtype)
print(b, b.dtype)
print(c, c.dtype)
print(d, d.dtype)
print(e, e.dtype)
print(f, f.dtype)
[ 1 16 31 46] int16
[ 1 10 20 30 40 50] int64
[ 1.  10.8 20.6 30.4 40.2 50. ] float32
[ 1.  10.8 20.6 30.4 40.2 50. ] float64
['правда' 'ложь'] <U10
[1 1 1 1 1] int8

Присваивать dtype python-классы int, float и другие имеет смысл, если вы хотите поменять только тип данных. Если есть желание сэкономить память, то следует использовать буквы-спецификации с указанием после них количества байтов (при выводе числовых типов данных показывается число битов, так 'i2' соответствует int16). Список допустимых в NumPy типов: i — целое число, b — булево значение, u — беззнаковое целое, f — вещественное число, c — комплексное число, m — timedelta (промежуток времени), M — datetime (дата и время), O — объект, S — строка, U — юникод-строка, V — фиксированный фрагмент памяти для других типов (void).

У numpy-массивов есть метод astype, который создает копию существующего массива, но с элементами другого типа. Таким образом, в процессе выполнения программы можно поменять тип данных элементов массива, если в этом возникает необходимость.

a = np.empty(4, dtype='i')
print(a)
a = a.astype('u1')
print(a)
b = a.astype(bool)
print(b)
[          0 -1073741824  -881360897       32500]
[  0   0 255 244]
[False False  True  True]