Python массивы. Библиотека NumPy
Библиотека NumPy( Numerical Python ) считается основной реализацией массивов Python. Она представляет высокопроизводительный, полнофункциональный тип n-мерного массива, который называется ndarray ( array ). Операции с array выполняются на два порядка быстрее, чем операции со списками. Многие популярные библиотеки data science, такие как pandas, SciPy, Keras и другие, построены на базе NumPy или зависят от нее.
Создадим массив на основе списка. NumPy рекомендует импортировать модуль numpy под именем np, чтобы к его компонентам можно было обращаться с префиксом "np".
>>> import numpy as np
>>> a = [2, 56, 46, 24, 12]
>>> numbers = np.array(a)
>>> type(numbers)
<class 'numpy.ndarray'>
>>> numbers
array([ 2, 56, 46, 24, 12])
Мы взяли обыкновенный список с различными значениями и преобразовали его в массив с помощью модуля numpy. Модуль numpy предоставляет различные функции для создания массивов. Мы воспользовались функцией array, которая в аргументе получила список а. Проверив с помощью функции type() тип объекта мы получили 'numpy.ndarray.
Приведем пример создания массива на основе списка из трех строк и трех столбцов:
>>> b = [[5, 6, 10], [25, 64, 17], [14, 25, 14]]
>>> mas = np.array(b)
>>> mas
array([[ 5, 6, 10],
[25, 64, 17],
[14, 25, 14]])
NumPy автоматически форматирует array на основание количества их измерений и выравнивает столбцы в каждой строке.
Список так же можно передавать напрямую переменной:
>>> numbers = np.array([ 1, 5, 47, 78])
>>> numbers
array([ 1, 5, 47, 78])
2. Атрибуты array
2.1. Определение типа элементов array
Для проверки типа элемента array можно воспользоваться атрибутом dtype:
>>> import numpy as np
>>> numbers_1 = np.array([[5, 7, 45], [14, 7, 9]])
>>> numbers_1
array([[ 5, 7, 45],
[14, 7, 9]])
>>> numbers_1.dtype
dtype('int32')
>>> numbers_2 = np.array([[0.5, 0.7, 0.45], [0.14, 0.7, 0.9]])
>>> numbers_2
array([[0.5 , 0.7 , 0.45],
[0.14, 0.7 , 0.9 ]])
>>> numbers_2.dtype
dtype('float64')
В примере есть два массива numbers_1 и numbers_2, с помощью dtype определяем их тип. Так как библиотека NumPy написана на языке C и в ней используется тип данных С. В результате мы получили, что первый массив принадлежит к типу dtype('int32')- целые числа, а второй к типу dtype('float64')- вещественные или числа с плавающей точкой.
2.2. Определение размерности array
Для определения размерности существует атрибут ndim, который содержит количество измерений array. Атрибут shape содержит кортеж, определяющий размерность array.
>>> import numpy as np
>>> numbers_1 = np.array([[5, 7, 45], [14, 7, 9]])
>>> numbers_1.ndim
2
>>> numbers_1.shape
(2, 3)
В примере numbers_1 состоит из двух строк и трех столбцов.
2.3. Определение количества и размера элементов
Количество элементов в массиве можно получить с помощью атрибута size.
>>> import numpy as np
>>> numbers_1 = np.array([[5, 7, 45], [14, 7, 9]])
>>> numbers_1.size
6
Количество байтов, необходимое для хранения элементов можно получить из атрибута itemsize.
>>> numbers_1.itemsize
4
Для компиляторов C с 32-разрядным int, размер равен 4. Если у вас 64-разрядный, у вас будет равен 8.
2.4. Перебор элементов array
Для перебора многомерной коллекции array можно воспользоваться циклом for:
>>> import numpy as np
>>> numbers_1 = np.array([[5, 7, 45], [14, 7, 9]])
>>> for row in numbers_1:
... for column in row:
... print(column, end=' ')
... print()
...
5 7 45
14 7 9
Если вы хотите получить все результаты в одно строку, можно воспользоваться атрибутом flat:
3. Создание массивов в Python по диапазонам
NumPy представляет множество функций для создания массивов в заданном диапазоне. Разберем самые распространённые.
3.1. Создание диапазонов функцией arange
В библиотеке NumPy существует функция arange для создания целочисленных диапазонов, аналогичной встроенной функции range в Python.
>>> import numpy as np
>>> np.arange(7)
array([0, 1, 2, 3, 4, 5, 6])
>>> np.arange(5, 10)
array([5, 6, 7, 8, 9])
>>> np.arange(100, 10, -10)
array([100, 90, 80, 70, 60, 50, 40, 30, 20])
При создании коллекций array вы можете воспользоваться встроенной функции Python range, но рекомендуется использовать именно arange, так как она оптимизирована для array. Все свойства arange аналогичны функции range.
3.2. Создание диапазонов чисел с плавающей точкой функцией linspace
Для создания диапазонов чисел с плавающей точкой можно воспользоваться функцикй limspace библиотеки NumPy.
>>> import numpy as np
>>> np.linspace(1.0, 2.0, num=5)
array([1. , 1.25, 1.5 , 1.75, 2. ])
>>> np.linspace(1.0, 5.0, num=10)
array([1. , 1.44444444, 1.88888889, 2.33333333, 2.77777778, 3.22222222, 3.66666667, 4.11111111, 4.55555556, 5. ])
В функции linspace первые два аргумента определяют начальное и конечное значение диапазона. Важно: конечное значение включается в array. Ключевой аргумент num необязательный. Он задает количество равномерно распределенных генерируемых значений. По умолчанию num = 50.
3.3. Изменение размерности array методом reshape
Методом reshape вы можете преобразовать одномерную коллекцию в многомерную. В примере создадим коллекцию array с помощью arange со значениями от 1 до 36 и с помощью метода reshape преобразуем ее в структуру из 6 строк и 6 столбцов.
>>> import numpy as np
>>> np.arange(1, 37).reshape(6, 6)
array([[ 1, 2, 3, 4, 5, 6],
[ 7, 8, 9, 10, 11, 12],
[13, 14, 15, 16, 17, 18],
[19, 20, 21, 22, 23, 24],
[25, 26, 27, 28, 29, 30],
[31, 32, 33, 34, 35, 36]])
>>> np.arange(1, 37).reshape(4, 9)
array([[ 1, 2, 3, 4, 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14, 15, 16, 17, 18],
[19, 20, 21, 22, 23, 24, 25, 26, 27],
[28, 29, 30, 31, 32, 33, 34, 35, 36]])
Во втором примере мы преобразовали в структуру 4 строк и 9 столбцов.
Размерность можно изменять для любой коллекции array, но при условии, что количество новой версии не будет отличаться от оригинала. Например, коллекцию из шести элементов, можно преобразовать в коллекцию 3*2 или 2*3. В нашем примере мы преобразовали коллекцию из 36 элементов в коллекцию 6*6 и 4*9. В случае неправильного преобразования, вы получите ошибку ValueError.
3.4. Заполнение array конкретными значениями. Функции zeros, ones, full
Функция zeros создает коллекцию содержащие 0. Первым аргументом должно быть целое число или кортеж целых чисел.
>>> import numpy as np
>>> np.zeros(7)
array([0., 0., 0., 0., 0., 0., 0.])
>>> np.zeros((3, 3))
array([[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.]])
Функция ones создает коллекцию содержащие 1.
>>> import numpy as np
>>> np.ones((3, 3))
array([[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.]])
По умолчанию функции zeros и ones создают коллекции array, содержащие значения float. Для изменения типа значения можно задать аргумент dtype:
>>> import numpy as np
>>> np.ones((3, 3), dtype=int)
array([[1, 1, 1],
[1, 1, 1],
[1, 1, 1]])
>>> np.zeros((3, 3), dtype=int)
array([[0, 0, 0],
[0, 0, 0],
[0, 0, 0]])
Функция full, возвращает элементы со значением и типом второго аргумента:
>>> import numpy as np
>>> np.full((3, 4), 55)
array([[55, 55, 55, 55],
[55, 55, 55, 55],
[55, 55, 55, 55]])
>>> np.full((2, 4), 21.2)
array([[21.2, 21.2, 21.2, 21.2],
[21.2, 21.2, 21.2, 21.2]])
3.5. Вывод больших коллекций array
При выводе больших коллекций array, NumPy исключает из вывода все строки и столбцы кроме первых трех и последних. Вместо исключенных данных проставляется знак многоточие.
>>> import numpy as np
>>> np.arange(1, 100001).reshape(100, 1000)
array([[ 1, 2, 3, ..., 998, 999, 1000],
[ 1001, 1002, 1003, ..., 1998, 1999, 2000],
[ 2001, 2002, 2003, ..., 2998, 2999, 3000],
...,
[ 97001, 97002, 97003, ..., 97998, 97999, 98000],
[ 98001, 98002, 98003, ..., 98998, 98999, 99000],
[ 99001, 99002, 99003, ..., 99998, 99999, 100000]])
4. Операторы array
4.1. Арифметические операции c массивами в Python
Арифметические операции с array выполняются поэлементно, то есть применяются к каждому элементу массива. Пример, если мы умножаем массив на 3, то каждый элемент будет умножен на 3. Так же и с остальными арифметическими операциями.
>>> import numpy as np
>>> numbers_1 = np.array([[5, 7, 45], [14, 7, 9]])
>>> numbers_1 * 3
array([[ 15, 21, 135],
[ 42, 21, 27]])
>>> numbers_1 ** 3
array([[ 125, 343, 91125],
[ 2744, 343, 729]], dtype=int32)
>>> numbers_1
array([[ 5, 7, 45],
[14, 7, 9]])
Важно, что при арифметических операциях, возвращается новая коллекция array, исходный массив numbers_1 не изменяется.
А вот расширенное присваивание изменяет каждый элемент левого операнда:
>>> import numpy as np
>>> numbers_1 = np.array([[5, 7, 45], [14, 7, 9]])
>>> numbers_1 += 10
>>> numbers_1
array([[15, 17, 55],
[24, 17, 19]])
4.2. Арифметические операции между коллекциями array
С коллекциями array можно выполнять арифметические операции, если они имеют одинаковые размеры. Результатом будет новая коллекция array:
>>> import numpy as np
>>> numbers_1 = np.array([[5, 7, 45], [14, 7, 9]])
>>> numbers_2 = np.array([[8, 12, -35], [4, 12, 25]])
>>> numbers_1 * numbers_2
array([[ 40, 84, -1575],
[ 56, 84, 225]])
>>> numbers_1 - numbers_2
array([[ -3, -5, 80],
[ 10, -5, -16]])
4.3. Сравнение коллекция array
Коллекции array можно сравнивать как между собой, так и с отдельными значениями. Сравнение выполняется поэлементно.
>>> import numpy as np
>>> numbers_1 = np.array([2, 4, 6, 8, 10])
>>> numbers_2 = np.array([1, 5, 6, 7, 12])
>>> numbers_1 > numbers_2
array([ True, False, False, True, False])
>>> numbers_1 == numbers_2
array([False, False, True, False, False])
>>> numbers_1 >= 5
array([False, False, True, True, True])
В результате сравнений создаются коллекции array с логическими значениями ( True или False), каждое из которых означает результат сравнения каждого элемента.
5. Вычислительные методы NumPy
При помощи различных методов мы можем проводить арифметические операции внутри коллекций, вычислить сумму всех элементов или найти наибольше значение. Приведем пример основных методов:
>>> import numpy as np
>>> grades = np.array([[3, 4, 5, 4], [2, 5, 4, 5], [5, 5, 4, 5]])
>>> grades
array([[3, 4, 5, 4],
[2, 5, 4, 5],
[5, 5, 4, 5]])
>>> grades.min()
2
>>> grades.max()
5
>>> grades.sum()
51
>>> grades.mean()
4.25
>>> grades.std()
0.924211375534118
>>> grades.var()
0.8541666666666666
Метод min() и max() находит наименьшее и наибольшее значение. Метод sum() - вычисляет сумму всех элементов, mean() - математическое ожидание, std() - стандартное отклонение, var() - дисперсию.
Эти методы могут применяться к конкретным осям array. К примеру, нам нужно вычислить средний бал по предмету. Для это в метод добавляется аргумент axis, который позволяет проводить вычисление по строкам или столбцам.
>>> grades.mean(axis=0)
array([3.33333333, 4.66666667, 4.33333333, 4.66666667])
>>> grades.mean(axis=1)
array([4. , 4. , 4.75])
Если axis=0, выполняется вычисления по всем значениям строк внутри каждого столбца.
Если axis=1, выполняется вычисления со всеми значениями столбца внутри каждой отдельной строки.
6. Индексирование и сегментация массивов в Python
Для одномерных коллекций array применяются, операции сегментации и индексирования, описанные в разделе "Сегментация последовательностей в Python". Ниже разберем сегментацию с двумерными коллекциями array.
-
Выбор элемента двумерной коллекции array
Для выбора элемента двумерной коллекции array укажите кортеж с индексами строки и столбца элемента в квадратных скобках.
>>> import numpy as np
>>> grades = np.array([[3, 4, 5, 4], [2, 5, 4, 5], [5, 5, 4, 5], [5, 4, 5, 3]])
>>> grades
array([[3, 4, 5, 4],
[2, 5, 4, 5],
[5, 5, 4, 5],
[5, 4, 5, 3]])
>>> grades[1, 2] # строка 1, столбец 2
4
-
Выбор подмножества строк двумерной коллекции array
Для выбора одной строки укажите в квадратных скобках только один индекс:
>>> grades[2]
array([5, 5, 4, 5])
Для выбора нескольких строк используйте синтаксис сегмента:
>>> grades[1:3]
array([[2, 5, 4, 5],
[5, 5, 4, 5]])
Для выбора нескольких несмежных строк используйте список индексов строк:
>>> grades[[1, 3]]
array([[2, 5, 4, 5],
[5, 4, 5, 3]])
-
Выбор подмножества столбцов двумерной коллекции array
Для выбора подмножества столбцов следует указать кортеж, в котором указаны выбираемые строки и столбцы:
>>> grades[:, 1]
array([4, 5, 5, 4])
Двоеточие указывает какие строки в столбце должны выбираться. В нашем случает " : " является сегментом и выбираются все строки. После запятой мы указали 1, значит выбрали столбец номер два.
Для выбора нескольких смежных столбцов используется синтаксис сегмента:
>>> grades[:, 1:3]
array([[4, 5],
[5, 4],
[5, 4],
[4, 5]])
Для выбора конкретных столбцов используйте список индексов этих строк:
>>> grades[:, [0, 2, 3]]
array([[3, 5, 4],
[2, 4, 5],
[5, 4, 5],
[5, 5, 3]])
7. Глубокое копирование. Метод copy
В случае если вам необходимо создать новую коллекцию с аналогичными данными, можно воспользоваться методом copy. Метод copy коллекций array возвращает новый объект array с глубокой копией данных объекта исходной коллекции.
>>> import numpy as np
>>> numbers_1 = np.array([21, 25, 12, 1, 78])
>>> numbers_1
array([21, 25, 12, 1, 78])
>>> numbers_2 = numbers_1.copy()
>>> numbers_2
array([21, 25, 12, 1, 78])
В итоге мы получили новый массив numbers_2, с которым далее мы можем работать, не изменяя основной массив.
8. Изменение размеров и транспонирование массива в Python
В NumPy существует много возможностей для изменения размера массивов.
8.1. Метод resize
Метод resize изменяет размер исходной коллекции array:
>>> import numpy as np
>>> numbers = np.array([21, 25, 12, 1, 78, 77])
>>> numbers
array([21, 25, 12, 1, 78, 77])
>>> numbers.resize(3, 2)
>>> numbers
array([[21, 25],
[12, 1],
[78, 77]])
8.2. Методы flatten и ravel
- Метод flatten выполняет глубокое копирование данных исходной коллекции
>>> import numpy as np
>>> numbers = np.array([21, 25, 12, 1, 78])
>>> numbers_fl = numbers.flatten()
>>> numbers_fl
array([21, 25, 12, 1, 78])
Чтобы проверить что numbers и numbers_fl не используют общие данные изменим элемент numbers_fl и выведем оба массива:
>>> numbers_fl[0] = 77
>>> numbers_fl
array([77, 25, 12, 1, 78])
>>> numbers
array([21, 25, 12, 1, 78])
Значение в numbers_fl изменилось, значит массивы уже не связаны между собой.
- метод ravel создает представление (поверхностную копию) исходной коллекции array, которое использует общие данные.
>>> numbers
array([21, 25, 12, 1, 78])
>>> numbers_ra = numbers.ravel()
>>> numbers_ra
array([21, 25, 12, 1, 78])
Чтобы проверить использование общих данных, изменим один элемент numbers_ra:
>>> numbers_ra[0] = 125
>>> numbers_ra
array([125, 25, 12, 1, 78])
>>> numbers
array([125, 25, 12, 1, 78])
В результате значения поменялись в обоих массивах.
8.3. Транспонирование строк и столбцов
С помощью атрибута T вы можете быстро транспонировать строки и столбцы маcсива, то есть сделать так чтобы строки стали столбцами, а столбцы строками.
>>> import numpy as np
>>> numbers = np.array([[45, 65, 48], [78, 45, 62]])
>>> numbers
array([[45, 65, 48],
[78, 45, 62]])
>>> numbers.T
array([[45, 78],
[65, 45],
[48, 62]])
Транспонирование не изменяет исходную коллекцию array.
8.4. Горизонтальное и вертикальное дополнение. Функции hstack и vstack
Добавление новых строк или столбцов, называется горизонтальным или вертикальным дополнением. Допустим у нас есть две коллекции array, и мы хотим объединить их в одну. Для этого можно воспользоваться функцией hstack() из библиотеки NumPy. Функцие hstack() передается кортеж с объединяемыми коллекциями:
>>> import numpy as np
>>> numbers_1 = np.array([21, 25, 12, 1, 78])
>>> numbers_2 = np.array([17, 54, 55, 24, 78])
>>> np.hstack((numbers_1, numbers_2))
array([21, 25, 12, 1, 78, 17, 54, 55, 24, 78])
В случае если нам требуется объединить массивы добавлением, можно воспользоваться функцией vstack():
>>> np.vstack((numbers_1, numbers_2))
array([[21, 25, 12, 1, 78],
[17, 54, 55, 24, 78]])