NumPy Ndarray: создание массива, генерация и типы данных / np 2

Основной элемент библиотеки NumPy — объект ndarray (что значит N-размерный массив). Этот объект является многомерным однородным массивом с заранее заданным количеством элементов. Однородный — потому что практически все объекты в нем одного размера или типа. На самом деле, тип данных определен другим объектом NumPy, который называется dtype (тип-данных). Каждый ndarray ассоциирован только с одним типом dtype.

Количество размерностей и объектов массива определяются его размерностью (shape), кортежем N-положительных целых чисел. Они указывают размер каждой размерности. Размерности определяются как оси, а количество осей — как ранг.

Еще одна странность массивов NumPy в том, что их размер фиксирован, а это значит, что после создания объекта его уже нельзя поменять. Это поведение отличается от такового у списков Python, которые могут увеличиваться и уменьшаться в размерах.

Простейший способ определить новый объект ndarray — использовать функцию array(), передав в качестве аргумента Python-список элементов.

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

Можно легко проверить, что новый объект — это ndarray, передав его функции type().

>>> type(a)
<type 'numpy.ndarray'>

Чтобы узнать ассоциированный тип dtype, необходимо использовать атрибут dtype.

Примечание: результат dtype, shape и других может быть разным для разных операционных систем и дистрибутивов Python.

>>> a.dtype 
dtype('int64')

Только что созданный массив имеет одну ось, а его ранг равняется 1, то есть его форма — (3,1). Для получения этих значений из массива необходимо использовать следующие атрибуты: ndim — для осей, size — для длины массива, shape — для его формы.

>>> a.ndim
1
>>> a.size
3
>>> a.shape
(3,)

Это был пример простейшего одномерного массива. Но функциональность массивов может быть расширена и до нескольких размерностей. Например, при определении двумерного массива 2×2:

>>> b = np.array([[1.3, 2.4],[0.3, 4.1]])
>>> b.dtype
dtype('float64')
>>> b.ndim
2
>>> b.size
4
>>> b.shape
(2, 2)

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

Еще один важный атрибут — itemsize. Он может быть использован с объектами ndarray. Он определяет размер каждого элемента массива в байтах, а data — это буфер, содержащий все элементы массива. Второй атрибут пока не используется, потому что для получения данных из массива применяется механизм индексов, речь о котором подробно пойдет в следующих разделах.

>>> b.itemsize
8
>>> b.data
<read-write buffer for 0x0000000002D34DF0, size 32, offset 0 at
0x0000000002D5FEA0>

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

Есть несколько вариантов создания массива. Самый распространенный — список из списков, выступающий аргументом функции array().

>>> c = np.array([[1, 2, 3],[4, 5, 6]])
>>> c
array([[1, 2, 3],
       [4, 5, 6]])

Функция array() также может принимать кортежи и последовательности кортежей.

>>> d = np.array(((1, 2, 3),(4, 5, 6)))
>>> d
array([[1, 2, 3],
       [4, 5, 6]])

Она также может принимать последовательности кортежей и взаимосвязанных списков.

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

Типы данных

Пока что рассматривались только значения простого целого числа и числа с плавающей запятой, но массивы NumPy сделаны так, чтобы включать самые разные типы данных. Например, можно включать строки:

Типы данных, поддерживаемые NumPy

Тип данныхОписание
boolБулевы значения (True или False) хранятся в виде байтов
intТип по умолчанию — целое число (то же, что long в C; обычно int64 или int32)
intcИдентичный int в C (обычно int32 или int64)
intpЦелое число для использования в качестве индексов (то же, что и size_t в C, обычно int32 или int64)
int8Байт (от — 128 до 127)
int16Целое число (от -32768 до 32767)
int32Целое число (от -2147483648 до 2147483647)
int64Целое число (от -9223372036854775808 до 9223372036854775807)
uint8Целое число без знака (от 0 до 255)
uint16Целое число без знака (от 0 до 65535)
uint32Целое число без знака (от 0 до 4294967295)
uint64Целое число без знака (от 0 до 18446744073709551615)
floatОбозначение float64
float16Число с плавающей точкой половинной точности; бит на знак, 5-битная экспонента, 10-битная мантисса
float32Число с плавающей точкой единичной точности; бит на знак, 8-битная экспонента, 23-битная мантисса
float64Число с плавающей точкой двойной точности; бит на знак, 11-битная экспонента, 52-битная мантисса
complexОбозначение complex128
complex64Комплексное число, представленное двумя 32-битными float (с действительной и мнимой частями)
complex128Комплексное число, представленное двумя 64-битными float (с действительной и мнимой частями)

Параметр dtype

Функция array() не принимает один аргумент. На примерах видно, что каждый объект ndarray ассоциирован с объектом dtype, определяющим тип данных, которые будут в массиве. По умолчанию функция array() можно ассоциировать самый подходящий тип в соответствии со значениями в последовательностях списков или кортежей. Их можно определить явно с помощью параметра dtype в качестве аргумента.

Например, если нужно определить массив с комплексными числами в качестве значений, необходимо использовать параметр dtype следующим образом:

>>> f = np.array([[1, 2, 3],[4, 5, 6]], dtype=complex)
>>> f
array([[ 1.+0.j, 2.+0.j, 3.+0.j],
       [ 4.+0.j, 5.+0.j, 6.+0.j]])

Функции генерации массива

Библиотека NumPy предоставляет набор функций, которые генерируют ndarray с начальным содержимым. Они создаются с разным значениями в зависимости от функции. Это очень полезная особенность. С помощью всего одной строки кода можно сгенерировать большой объем данных.

Функция zeros(), например, создает полный массив нулей с размерностями, определенными аргументом shape. Например, для создания двумерного массива 3×3, можно использовать:

>>> np.zeros((3, 3))
array([[ 0., 0., 0.],
       [ 0., 0., 0.],
       [ 0., 0., 0.]])

А функция ones() создает массив, состоящий из единиц.

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

По умолчанию две функции создают массивы с типом данных float64. Полезная фишка — arrange(). Она генерирует массивы NumPy с числовыми последовательностями, которые соответствуют конкретным требованиям в зависимости от переданных аргументов. Например, для генерации последовательности значений между 0 и 10, нужно передать всего один аргумент — значение, которое закончит последовательность.

>>> np.arange(0, 10) 
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

Если в начале нужен не ноль, то необходимо обозначить уже два аргумента: первый и последний.

>>> np.arange(4, 10) 
array([4, 5, 6, 7, 8, 9])

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

>>> np.arange(0, 12, 3) 
array([0, 3, 6, 9])

Оно может быть и числом с плавающей точкой.

>>> np.arange(0, 6, 0.6)
array([ 0. , 0.6, 1.2, 1.8, 2.4, 3. , 3.6, 4.2, 4.8, 5.4])

Пока что в примерах были только одномерные массивы. Для генерации двумерных массивов все еще можно использовать функцию arrange(), но вместе с reshape(). Она делит линейный массив на части способом, который указан в аргументе shape.

>>> np.arange(0, 12).reshape(3, 4)
array([[ 0, 1, 2, 3],
       [ 4, 5, 6, 7],
       [ 8, 9, 10, 11]])

Похожая на arrange() функция — linspace(). Она также принимает в качестве первых двух аргументов первое и последнее значения последовательности, но третьим аргументом является не интервал, а количество элементов, на которое нужно разбить последовательность.

>>> np.linspace(0,10,5)
array([ 0. , 2.5, 5. , 7.5, 10. ])

Еще один способ получения массива — заполнение его случайными значениями. Это можно сделать с помощью функции random() из модуля numpy.random. Эта функция генерирует массив с тем количеством элементов, которые указаны в качестве аргумента.

>>> np.random.random(3)
array([ 0.78610272, 0.90630642, 0.80007102])

Полученные числа будут отличаться с каждым запуском. Для создания многомерного массива, нужно передать его размер в виде аргумента.

>>> np.random.random((3,3))
array([[ 0.07878569, 0.7176506 , 0.05662501],
       [ 0.82919021, 0.80349121, 0.30254079],
       [ 0.93347404, 0.65868278, 0.37379618]])