Библиотека Numpy дает мощный и удобный высокоуровневый аппарат для работы с многомерными данными. Для работы с ними в Numpy разработана своя собственная структура данных — массив numpy.ndarray
. Именно под эту структуру оптимизирована работа всего функционала библиотеки.
В этом уроке познакомимся с тем, как создавать массив ndarray из стандартных типов данных языка Python и попробуем на практике решить ряд простых аналитических задач.
Структура данных библиотеки Numpy
Чтобы создать структуру numpy.ndarray
, нужно конвертировать список list
. Для конвертации из множества set
требуется дополнительное приведение типа данных.
Рассмотрим на таком примере:
# Импортируем библиотеку numpy с псевдонимом np
import numpy as np
# Создаем простой пример списка языка Python
simple_list = [1, 2, 3, 4, 5]
# Конвертируем созданный список в массив Numpy
my_first_ndarray = np.array(simple_list, dtype=int)
# Тип созданного объекта
print(type(my_first_ndarray))
# => <class 'numpy.ndarray'>
# Результат стандартного вывода
print(my_first_ndarray)
# => [1 2 3 4 5]
А теперь разберем этот код подробнее. Сам пример показывает встроенную функциональность для создания структуры numpy.ndarray
. Мы импортируем библиотеку Numpy, создаем короткий список значений simple_list
, а затем конвертируем в массив my_first_ndarray
. Для этого вызываем конструктор np.array()
с объектами для конвертации.
С учетом примера выше, обратная конвертация в список происходит так:
print(ndarray_from_list.tolist())
Конвертация из списка Python — это самая популярная операция, с помощью которой создается структура numpy.ndarray
.
Так происходит потому, что обмен данными между функциями и сервисами удобно производить в стандартных структурах данных языка. Другими словами, можно не вводить структуры данных сторонних библиотек и не усложнять программу.
Но при разработке сложных программ модуль numpy.ndarray
может быть только частью общей структуры. В таких случаях используют стандартные типы данных языка для обмена данными между функциональными частями программ.
В итоге порядок работы с данными при работе с Numpy выглядит следующим образом:
Как правило, вычислительные и аналитические модули в виде входных данных ожидают списки значений. Всю оптимизацию они делают уже внутри себя в собственных абстракциях, невидимых извне. Это сделано для простоты интеграции.
Допустимые типы данных
Поговорим подробнее о типах элементов массива, которые можно использовать для numpy.ndarray
. Продолжим работать с тем же примером и воспользуемся следующим методом:
# Проверяем тип полученного массива
print(my_first_ndarray.dtype.type)
# => <class 'numpy.int64'>
Как и ожидалось, тип данных — int64. Необязательно ограничиваться только им:
# Целочисленный массив
print(np.array([1, 2, 3], dtype=int).dtype.type)
# => <class 'numpy.int64'>
# Массив строк
print(np.array([1, 2, 3], dtype=str).dtype.type)
# => <class 'numpy.str_'>
# Массив чисел с плавающей запятой
print(np.array([1, 2, 3], dtype=float).dtype.type)
# => <class 'numpy.float64'>
Обратите внимание, что для экземпляра структуры numpy.ndarray
нельзя использовать сразу несколько типов данных. Проще говоря, все элементы в массиве должны быть однотипные. Посмотрим, как конструктор сам определит тип данных при конвертации:
# Все элементы списка целочисленные
print(np.array([1, 2, 3]).dtype.type)
# => <class 'numpy.int64'>
# Все элементы списка — это строки
print(np.array(['1', '2', '3']).dtype.type)
# => <class 'numpy.str_'>
# Элементы списка как текстовые, так и целочисленные
print(np.array(['1', 2, 3]).dtype.type)
# => <class 'numpy.str_'>
Заметим, что ошибки при конвертации смешанного типа элементов массива не произошло. Конвертор просто привел все данные к строковому типу.
Как Numpy работает на практике
Функциональность библиотеки Numpy настолько интуитивна, что уже сейчас можно решить простую аналитическую задачку.
Представим продажи ноутбуков в магазине за одну неделю:
День | Магазин №1 |
---|---|
0 | 7 |
1 | 4 |
2 | 3 |
3 | 8 |
4 | 15 |
5 | 21 |
6 | 25 |
На практике такие данные обычно хранятся в табличном виде в базе данных. Чтобы упростить пример, мы пропустили этап выгрузки — подразумевается, что данные приходят в вычислительный модуль уже в виде списка значений.
Поработаем с данными с помощью библиотеки Numpy:
# Импортируем библиотеку numpy с псевдонимом np
import numpy as np
# Создаем список продаж — представим, что считали его из базы данных
orders_list = [7, 4, 3, 8, 15, 21, 25]
# Конвертируем созданный список в массив Numpy
orders_ndarray = np.array(orders_list, dtype=int)
# Тип созданного объекта
print(type(orders_ndarray))
# => <class 'numpy.ndarray'>
# Результат стандартного вывода
print(orders_ndarray)
# => [ 7 4 3 8 15 21 25]
Попробуем найти день недели с самыми низкими продажами. Опыт работы с Python подсказывает, что метод будет называться min()
или minimum()
. Найдем минимальное количество продаж и заодно день недели, в который оно совершено:
# Находим минимальный элемент массива
print(orders_ndarray.min())
# => 3
# Находим порядковый номер минимального элемента массива
print(orders_ndarray.argmin())
# => 2
Чтобы найти наибольшее количество продаж, достаточно поменять одну функцию:
# Находим максимальный элемент массива
print(orders_ndarray.max())
# => 25
На практике часто анализ не ограничивается только одной неделей продаж и одним магазином. В этом случае набор данных представлен в виде списка списков элементов — это уже двумерная структура, которая в математике называется матрицей.
В Numpy реализация инициализации массивов и функций работы с ними не зависит от размерности данных, что существенно упрощает разработку.
В современных библиотеках можно применять одну и ту же функцию к различным типам данных. Рассмотрим это на примере, похожем на предыдущий. Найдем день с самыми низкими доходами во всей сети магазинов. Рассмотрим недельные продажи в четырех магазинах:
День | Магазин №1 | Магазин №2 | Магазин №3 | Магазин №4 |
---|---|---|---|---|
0 | 7 | 1 | 7 | 8 |
1 | 4 | 2 | 4 | 5 |
2 | 3 | 5 | 2 | 3 |
3 | 8 | 12 | 8 | 7 |
4 | 15 | 11 | 13 | 9 |
5 | 21 | 18 | 17 | 21 |
6 | 25 | 16 | 25 | 17 |
Мы ожидаем, что функционально все должно быть реализовано похожим образом. Давайте в этом убедимся, взглянув на код:
# Импортируем библиотеку numpy с псевдонимом np
import numpy as np
# Создаем «список списков продаж»
orders_list = [
[7, 1, 7, 8],
[4, 2, 4, 5],
[3, 5, 2, 3],
[8, 12, 8, 7],
[15, 11, 13, 9],
[21, 18, 17, 21],
[25, 16, 25, 17]
]
# Конвертируем созданный «список списков» в массив Numpy
orders_ndarray = np.array(orders_list, dtype=int)
# Описываем тип созданного объекта
print(type(orders_ndarray))
# => <class 'numpy.ndarray'>
# Находим минимальный элемент массива
print(orders_ndarray.min())
# => 1
В приведенном примере метод min()
находит минимальный элемент среди всех значений массива.
Большинство функций в Numpy реализованы так, что методы и функции выполняют одинаковые операции, вне зависимости от типа данных на входе.
В программировании такой подход называется полиморфизмом. Он упрощает разработку и делает код более простым для анализа и поддержки.
Выводы
Сегодня мы познакомились с основной структурой данных библиотеки Numpy — массивом numpy.ndarray
.
В работе с ним мы используем указанный тип данных — это обусловлено оптимизацией работы функций внутри библиотеки. У Numpy понятный интерфейс для конвертации типа данных list
из стандартной библиотеки Python.
Новые знания мы сразу закрепили на практической задаче — вычислили день с самыми низкими доходами в сети магазинов. Эта задача показывает, насколько Numpy упрощает работу с входными данными разной размерности.
Самостоятельная работа
Первичный статистический анализ данных — одна из самых частых задач для аналитика. Представим, что в работу поступил список ежедневных кликов сайта компании, который был собран за 365 дней. В руках аналитика оказался Python-интерпретатор с предустановленной библиотекой быстрых вычислений Numpy. Поможем аналитику найти нужные статистические показатели и ключевые значения. Пройдем этот процесс по шагам:
Шаг 1. Чтобы работать со списком входных значений в нашем вычислительном модуле, нужно сконвертировать список в нужный формат данных. Напишите функцию create_click_numbers_ndarray()
, которая возвращает массив numpy.ndarray
, созданный из списка целочисленных значений.
Нажмите, чтобы увидеть ответ
def create_click_numbers_ndarray(input_click_numbers):
return np.array(
input_click_numbers
)
Шаг 2. Найдите размах выборки — разницу между максимальным и минимальным элементами. Эта простая характеристика позволяет оценить величину разброса значений кликов на сайт.
Нажмите, чтобы увидеть ответ
delta = create_click_numbers_ndarray(input_click_numbers).max() - create_click_numbers_ndarray(input_click_numbers).min()
Дополнительные материалы
Остались вопросы? Задайте их в разделе «Обсуждение»
Вам ответят команда поддержки Хекслета или другие студенты
Для полного доступа к курсу нужен базовый план
Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.