Зарегистрируйтесь для доступа к 15+ бесплатным курсам по программированию с тренажером

Многомерные массивы в Numpy Python: Numpy-массивы

Numpy

Библиотека 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

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

Допустимые типы данных

Поговорим подробнее о типах элементов массива, которые можно использовать для 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 упрощает вычисления работу с входными данными разной размерности.


Самостоятельная работа

Нажмите, чтобы увидеть тестовые данные
import random
random.seed(42)
min_num = 1200
max_num = 2500
input_click_numbers = [random.randrange(min_num, max_num) for _ in range(365)]

Первичный статистический анализ данных — одна из самых частых задач для аналитика. Представим, что в работу поступил список ежедневных кликов сайта компании, который был собран за 365 дней. В руках аналитика оказался Python-интерпретатор с предустановленной библиотекой быстрых вычислений Numpy. Поможем аналитику найти нужные статистические показатели и ключевые значения. Пройдем этот процесс по шагам:

Шаг 1. Для любого инструмента важна его версия, чтобы ориентироваться на актуальную документацию и не вызывать конфликтов с другими библиотеками. Импортируйте модуль numpy с псевдонимом np и выведите его версию.

Нажмите, чтобы увидеть ответ
def test(capsys):
    expected = '1.0.0'
    assert np.__version__ >= expected

import numpy as np
capsys = np.__version__
test(capsys)

Шаг 2. Чтобы работать со списком входных значений в нашем вычислительном модуле, нужно сконвертировать список в нужный формат данных. Напишите функцию create_click_numbers_ndarray(), которая возвращает массив numpy.ndarray, созданный из списка целочисленных значений.

Нажмите, чтобы увидеть ответ
def test(create_click_numbers_ndarray, input_click_numbers):
    # shape
    assert create_click_numbers_ndarray(input_click_numbers).shape[0] == 365
    # type
    assert create_click_numbers_ndarray(input_click_numbers).dtype == int

def create_click_numbers_ndarray(input_click_numbers):
    return np.array(
        input_click_numbers
    )

test(create_click_numbers_ndarray, input_click_numbers)

Шаг 3. Найдите размах выборки — разницу между максимальным и минимальным элементами. Эта простая характеристика позволяет оценить величину разброса значений кликов на сайт.

Нажмите, чтобы увидеть ответ
def test(capsys):
    expected = 1297
    assert round(capsys) == expected

capsys = create_click_numbers_ndarray(input_click_numbers).max() - create_click_numbers_ndarray(input_click_numbers).min()
test(capsys)

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

Нажмите, чтобы увидеть ответ
def test(capsys):
    expected = 1829
    assert round(capsys) == expected

capsys = create_click_numbers_ndarray(input_click_numbers).mean()
test(capsys)

Шаг 5. Если общая статистическая картина понятна аналитику, то для других сотрудников компании будет интереснее другое. Они захотят разобраться с конкретными крайними случаями в значениях данных, дать им бизнес оценку и обоснование. Найдите день в году, в который было совершено наибольшее количество кликов.

Нажмите, чтобы увидеть ответ
def test(capsys):
    expected = 362
    assert capsys == expected

capsys = create_click_numbers_ndarray(input_click_numbers).argmax()
test(capsys)

Шаг 6. Найдите день в году, в который было совершено наименьшее количество кликов.

Нажмите, чтобы увидеть ответ
def test(capsys):
    expected = 156
    assert capsys == expected

capsys = create_click_numbers_ndarray(input_click_numbers).argmin()
test(capsys)

Дополнительные материалы

  1. Русскоязычный туториал по NumPy

Аватары экспертов Хекслета

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят команда поддержки Хекслета или другие студенты

Об обучении на Хекслете

Для полного доступа к курсу нужен базовый план

Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.

Получить доступ
1000
упражнений
2000+
часов теории
3200
тестов

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

  • 130 курсов, 2000+ часов теории
  • 1000 практических заданий в браузере
  • 360 000 студентов
Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff
Рекомендуемые программы
профессия
от 5 025 ₽ в месяц
новый
Сбор, анализ и интерпретация данных
9 месяцев
с нуля
Старт 2 мая

Используйте Хекслет по-максимуму!

  • Задавайте вопросы по уроку
  • Проверяйте знания в квизах
  • Проходите практику прямо в браузере
  • Отслеживайте свой прогресс

Зарегистрируйтесь или войдите в свой аккаунт

Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»