Перейти к основному содержимому

Анализ данных - pandas, NumPy, SciPy

Разработчику Архитектору

Анализ данных и научные вычисления

Программирование на Python давно вышло за пределы сценариев автоматизации и веб-разработки, заняв ведущие позиции в области обработки информации, моделирования и принятия решений на основе данных. Эта трансформация стала возможной благодаря формированию зрелой экосистемы библиотек, объединённых общей философией эффективности, ясности и научной строгости. Среди них особое место занимают три кита — NumPy — фундамент для численных операций, Pandas — инструментарий для структурированного анализа, и Matplotlib/Seaborn/Plotly — среда визуализации. Вместе они образуют каркас, на котором строятся как академические исследования, так и промышленные решения — от прогнозирования спроса в ритейле до обработки сигналов в телемедицине.

Начнём с основания — с NumPy. Теория массивов, dtype и линейная алгебра в коде — NumPy — массивы, векторы и матрицы; готовые скрипты с разбором каждой строки — Lab 1129. Математика векторов и матриц — 342, 343.

Если воспринимать этот раздел как карту, то логика пути такая:

  • NumPy — быстрые вычисления — 337 + Lab 1129;
  • Pandas превращает сырые данные в табличную рабочую модель;
  • визуализация помогает увидеть закономерности и объяснить выводы другим.

Такой порядок изучения наиболее практичен для начинающего разработчика.

Маршрут Pandas

NumPy

NumPy — фундамент численных вычислений в Python: массивы ndarray, векторизация, матричные операции. Список Python хранит ссылки на объекты; NumPy — сплошной блок чисел одного типа, поэтому операции делегируются оптимизированному C-коду.

Подробно: 337 — NumPy: массивы, векторы и матрицы (справочник функций, LA в коде, dtype). Практика: Lab 1129. Теория LA: Векторы, Матрицы.


import numpy as np

a = np.array([1, 2, 3, 4])
b = np.array([[1, 2], [3, 4]])
print(np.mean(a), b.shape) # 2.5 (2, 2)

Краткий справочник частых вызовов — в 337#numpy-chasto-funktsii. Pandas внутри хранит числовые колонки как ndarray; без понимания NumPy сложнее осознанно работать с df.values и df.to_numpy().


Pandas

Если NumPy — это фундамент для чисел, то Pandas — это каркас для таблиц. Название библиотеки происходит от сокращения panel Данные — эконометрического термина, обозначающего наборы наблюдений, упорядоченных по двум измерениям — объектам (например, клиентам, товарам, регионам) и временным моментам (дням, месяцам, кварталам). Именно такие данные — гетерогенные, разреженные, с именованными колонками и потенциально пропущенными значениями — составляют подавляющее большинство рабочих задач — логи серверов, выгрузки CRM, финансовые отчёты, результаты A/B-тестов.

Галерея готовых скриптов с построчным разбором — DataFrame, фильтрация, groupby, очистка, merge, экспорт — в Pandas — типовые операции. Те же задачи в ExcelExcel и Google Sheets — формулы — формулы с разбором. Базовое чтение .txt и CSV через stdlib — Python — работа с файлами и текстом. Справочник команд — Pandas — типовые операции при анализе данных; merge и своды — Pandas — объединение таблиц, своды и временные ряды.

Pandas не заменяет NumPy; он надстраивается над ним. Внутреннее представление числовых колонок в Pandas — это всё те же массивы ndarray, оптимизированные на скорости. Но поверх добавляются слои абстракции — именованные оси, гибкая индексация, унифицированная обработка пропущенных данных, встроенные методы фильтрации и группировки. Это превращает техническую операцию — "найти средний чек по регионам за третий квартал" — в последовательность читаемых, почти разговорных команд.


Основные структуры — Series и DataFrame

В основе Pandas лежат две ключевые структуры данных.

Series — это одномерный индексированный массив, допускающий элементы произвольного (но одного) типа. По сути, это улучшенный словарь с целочисленной или меткой-индексом, где каждому ключу сопоставлено значение. При этом индекс не обязан быть последовательным или уникальным (хотя уникальность рекомендуется), а значения могут включать специальный маркер пропущенности — pd.NA или np.nan. Series часто возникает как результат выделения одной колонки из таблицы или агрегации по группе.

DataFrame — это двумерная табличная структура — упорядоченный набор колонок, каждая из которых является объектом Series, при этом все колонки разделяют общий индекс — набор меток строк. Это и есть программная реализация привычной электронной таблицы — строки — отдельные записи (например, заказы), колонки — их атрибуты (дата, клиент, сумма, статус). Важно, что колонки могут иметь разные типы — числа, строки, даты, булевы значения — Pandas корректно хранит и обрабатывает такие смешанные данные, что невозможно в "голом" NumPy.

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


Загрузка и сохранение данных

Анализ начинается с получения данных, и Pandas предоставляет унифицированный интерфейс для работы с самыми распространёнными форматами.

pd.read_csv() — самая востребованная функция. Она автоматически определяет разделитель (запятая, точка с запятой, табуляция), обрабатывает кавычки и экранирование, распознаёт даты, интерпретирует пустые ячейки как пропущенные. Для нестандартных случаев доступны десятки параметров — указание кодировки (encoding='utf-8', encoding='cp1251'), явное задание типов колонок (dtype={'id': 'Int64', 'price': 'float64'}), пропуск строк заголовка или итогов, обработка тысячных разделителей (thousands=' '). Эта гибкость позволяет загружать даже "некорректные" CSV-файлы, сформированные вручную или экспортированные из устаревших систем.

Аналогично работают pd.read_excel() (поддержка .xlsx, .xls, выбор листа по имени или индексу), pd.read_json(), pd.read_sql() (прямое выполнение SQL-запроса к СУБД через SQLAlchemy), pd.read_parquet() (высокопроизводительный столбцовый формат для big Данные). Обратные операции — to_csv(), to_excel() и другие — обеспечивают сериализацию результатов в нужный формат для передачи коллегам, загрузки в BI-системы или архивирования. Таблицы read_* / to_*, выбор строк, groupby, статистика и строковые методы — в типовых операциях Pandas.

При чтении из файлов Pandas стремится к максимальной автоматизации, но эта автоматизация не всегда совпадает с ожиданиями. Например, колонка с ID, содержащая ведущие нули ('00123'), будет интерпретирована как число 123, если не указан тип str. Колонка с датами в нестандартном формате может остаться строкой. Поэтому всегда полезно после загрузки выполнить df.info() — краткий отчёт о структуре — количество строк, тип каждой колонки, объём памяти и число непустых значений.


Подготовка данных

Шпаргалка команд

Таблица типовых вызовов (isnull().sum(), dropna(), rename, groupby и др.) — очистка и подготовка в Pandas. Обзор всех блоков EDA (импорт, фильтр, статистика, строки) — Pandas — типовые операции при анализе данных. Готовые скрипты с разбором для лабораторных — примеры в Lab.

Реальные данные редко бывают идеальными. Пропущенные значения — правило. Pandas вводит единый механизм их представления: в числовых колонках — np.nan, в строковых и категориальных — pd.NA. Оба значения ведут себя одинаково при фильтрации и агрегации: большинство статистических функций имеют параметр skipna=True по умолчанию, то есть игнорируют пропуски.

Обнаружить их можно с помощью методов isna() и notna(), возвращающих булеву маску той же формы, что и исходный объект. На основе этой маски легко посчитать, сколько строк содержат хотя бы один пропуск (df.isna().any(axis=1).sum()), или выделить "чистые" записи (df.dropna()). Однако просто удалить строки — не всегда оптимальное решение: при большом объёме пропущенных данных это может привести к потере репрезентативности выборки.

Альтернатива — заполнение. Метод fillna() позволяет подставить константу (value=0) или медиану колонки; для переноса значения с предыдущей строки удобны df.ffill() / df.bfill() (в старых примерах встречается fillna(method='ffill')). Для числовых данных часто используется медиана или мода колонки, как более устойчивые к выбросам, чем среднее. Важно документировать выбранный подход: импутация (восстановление пропущенных значений) — это гипотеза о структуре данных, влияющая на интерпретацию результатов.


Фильтрация, трансформация и группировка

Фильтрация в Pandas основана на булевых индексах. Выражение df['age'] > 30 возвращает серию True/False, которая, будучи подана в квадратные скобки, выбирает только те строки, где условие истинно. Условия можно комбинировать с помощью побитовых операторов & (и), | (или), ~ (не) над сериями True/False, заключая каждое условие в скобки из-за приоритета операций: df[(df['city'] == 'Москва') & (df['income'] > 100000)].

# выбор колонок + фильтр (типичное ДЗ на CSV маркетплейса)
subset = df.loc[df["price"] > 40, ["product_name", "price", "review_count"]]
print(subset.head())

Очистка «грязных» чисел и apply

Цены из CSV часто приходят как строки "$49.99". Сначала убирают символ валюты, затем приводят к float:

df["price"] = (
df["price"]
.astype(str)
.str.replace("$", "", regex=False)
.str.replace(",", "", regex=False)
.astype(float)
)

Метод apply применяет функцию к каждой строке (axis=1) или к каждому значению столбца (axis=0):

def price_tier(row):
if row["price"] > 100:
return "premium"
if row["price"] > 40:
return "mid"
return "budget"

df["tier"] = df.apply(price_tier, axis=1)

Для простых формул быстрее векторизация: df["tier"] = np.where(df["price"] > 100, "premium", "budget") (нужен import numpy as np). apply уместен, когда логика многошаговая. Примеры — Lab 1113, Lab 1148 — продажи.

Трансформация колонок выполняется через метод assign(), который возвращает новый DataFrame с дополнительными или изменёнными колонками, не затрагивая оригинал. Он принимает именованные аргументы, где имя — название колонки, а значение — либо константа, либо результат применения функции к существующим колонкам. Например, df.assign(discount=lambda x: x['price'] * 0.1) создаёт колонку discount, равную 10% от цены. Такой подход поощряет функциональный стиль — каждая операция — чистая функция, вход — DataFrame, выход — новый DataFrame.

Группировка — один из самых мощных инструментов. Метод groupby() разбивает данные на подмножества по значению одной или нескольких колонок (например, по региону и месяцу), после чего к каждой группе можно применить агрегирующую функцию — sum(), mean(), count(), first(), last(), а также пользовательскую через agg(). Результат — сводная таблица, где строки соответствуют уникальным комбинациям ключей группировки, а колонки — агрегированным показателям. При этом можно задавать разные функции для разных колонок — средний чек, число заказов, медианное время доставки — всё в одном вызове.

summary = sales.groupby(['region', 'quarter']).agg(
total_revenue=('amount', 'sum'),
avg_order=('amount', 'mean'),
order_count=('order_id', 'count'),
median_delivery=('delivery_days', 'median')
)

Разбор:

  • groupby(['region', 'quarter']) делит таблицу на группы по региону и кварталу.
  • agg(...) задаёт именованные агрегаты: слева имя итоговой колонки, справа исходная колонка и функция.
  • sum считает выручку, mean средний чек, count число заказов, median типичную длительность доставки.
  • На выходе получается компактная сводная таблица для управленческого отчёта.

Этот код читается почти как спецификация бизнес-требования, что делает его эффективным в исполнении и понятным при ревью.


Интеграция с визуализацией

Хотя Pandas не является библиотекой для построения графиков, он предоставляет удобный метод .plot(), который, по сути, является "обёрткой" над Matplotlib. Вызов df.plot(x='date', y='revenue', kind='line') построит временной ряд, df['category'].value_counts().plot(kind='bar') — столбчатую диаграмму распределения категорий. Это позволяет быстро получить первичное визуальное представление о данных без перехода в отдельный инструмент.

Такая интеграция сознательно ограничена: Pandas не стремится конкурировать с Matplotlib, Seaborn или Plotly в гибкости оформления. Его цель — обеспечить мост между анализом и визуализацией, чтобы исследователь мог, не прерывая поток мысли, перейти от расчёта статистик к их графическому отображению. Для сложных, публикуемых диаграмм всё равно потребуется более тонкая настройка через низкоуровневые библиотеки — но Pandas упрощает подготовку данных для этих библиотек — агрегированные таблицы, отфильтрованные выборки, сгруппированные сводки.


Практическое значение и границы

Pandas — это инструмент для аналитика, а не для инженера инфраструктуры. Он оптимизирован под интерактивную работу — исследование, итеративное уточнение гипотез, прототипирование отчётов. Для обработки данных объёмом в десятки гигабайт, требующей распределённых вычислений, используются другие решения — Dask (имитация API Pandas на кластере), Modin (ускорение через параллелизацию), PySpark (интеграция с экосистемой Apache Spark), Polars (быстрая обработка в RAM на одной машине). Сводная таблица "одна операция — четыре синтаксиса" (Pandas, Polars, SQL, PySpark) — напоминалка по табличным данным.

Тем не менее, знание Pandas необходимо даже в этих сценариях: Dask и Modin намеренно копируют его интерфейс, чтобы снизить порог входа. Более того, на этапе проектирования пайплайнов часто сначала пишут прототип на Pandas (на подвыборке), а затем переносят логику в распределённую среду. Таким образом, Pandas остаётся языком описания аналитических задач — стандартом де-факто для формулировки того, что нужно сделать с данными.

Углублённый практикум: объединение таблиц, своды и временные ряды. Сквозной проект с GUI: практикум Pandas Data Viewer (Tkinter + загрузка CSV/Excel, поиск, describe()). Нейросети с GUI: практикум PyTorch — MNIST. Классическое ML и нейросети: scikit-learn, PyTorch.


Минимальный практический маршрут

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

  1. Загрузить один CSV в Pandas и проверить df.info()/df.head() (команды — Pandas — типовые операции при анализе данных, примеры с разбором, очистка — Очистка и подготовка данных в Pandas).
  2. Убрать явные пропуски и дубликаты.
  3. Построить 2-3 базовых графика распределения и тренда.
  4. Сформировать сводную таблицу с ключевыми агрегатами.
  5. Если нужна предиктивная модель — начать с scikit-learn, а не сразу с нейросетей.

Визуализация данных

Визуализация — это неотъемлемая часть анализа. Человеческий мозг обрабатывает визуальную информацию на порядки быстрее, чем числовую таблицу; графики позволяют мгновенно выявлять тренды, аномалии, кластеры и корреляции, которые могли бы остаться незамеченными при простом просмотре статистик. Однако эффективная визуализация требует сознательного проектирования — выбор типа диаграммы, шкалы, цветовой палитры, подписей — всё это влияет на достоверность и убедительность выводов. В Python этот процесс поддерживается тремя взаимосвязанными библиотеками, каждая из которых решает свою задачу в иерархии абстракций.


Matplotlib

Matplotlib — старейшая и наиболее фундаментальная библиотека для построения графиков в Python. Подробная глава с архитектурой, API, экспортом и типичными ошибками — Matplotlib — графики; галерея скриптов — примеры в лаборатории. PDF из графика вставляют в текстовый отчёт — LaTeX — формулы для отчётов.

Её архитектура, вдохновлённая MATLAB, задаёт базовые понятия, на которых строятся все остальные инструменты — фигура (Figure) как контейнер верхнего уровня, оси (Axes) как область для нанесения данных, холст (Canvas) как поверхность рендеринга. Именно Matplotlib управляет шрифтами, раскладкой элементов, экспортом в PNG, PDF, SVG и другими форматами.

Ключевая особенность Matplotlib — гибкость через многоуровневый API. На самом низком — процедурный интерфейс pyplot (plt.plot(), plt.xlabel()), имитирующий MATLAB: простой для старта, но быстро становящийся громоздким при построении сложных композиций. На высшем — объектно-ориентированный подход, где явно создаются экземпляры Figure и Axes, и все операции выполняются через их методы (ax.plot(), ax.set_xlabel()). Этот стиль требует больше кода, но даёт полный контроль над каждым элементом графика, позволяет встраивать графики в GUI-приложения и обеспечивает воспроизводимость при автоматической генерации отчётов.

Стандартные стили Matplotlib консервативны, шрифты могут выглядеть устаревшими, цветовые палитры — неоптимальными для восприятия. Но именно эта "нейтральность" — преимущество: библиотека не навязывает интерпретацию, а предоставляет холст. Все детали — от толщины линий до расположения легенды — настраиваются явно, что делает графики предсказуемыми и пригодными для публикации в научных журналах, где строгие требования к форматированию.

Практически все высокоуровневые библиотеки визуализации (включая Pandas .plot()) в качестве бэкенда используют Matplotlib. Это означает, что навыки работы с его объектной моделью остаются востребованными даже при использовании более удобных обёрток — зная, как устроен Axes, можно донастроить любой график, построенный через Seaborn или Pandas.


Seaborn

Если Matplotlib — инструментарий для построения графиков, то Seaborn — фреймворк для анализа через графики. Его цель — облегчить визуальное исследование структуры данных, особенно многомерных — распределений, корреляций, отношений между категориями и непрерывными переменными. Seaborn берёт за основу концепции из статистической графики (statistics graphics), заложенные в пакеты вроде R’s ggplot2, и реализует их в Pythonic-стиле.

Главная сила Seaborn — в декларативности. Вместо того чтобы вручную вычислять гистограммы, ящики с усами или линии тренда, исследователь описывает какие переменные и в каком отношении он хочет увидеть. Например, вызов sns.scatterplot(data=df, x='income', y='spending', hue='region') автоматически:

  • построит точки на плоскости "доход–расход",
  • раскрасит их по значениям колонки region,
  • добавит легенду с названиями регионов,
  • выберет воспринимаемую цветовую палитру для категорий,
  • настроит подписи осей на основе имён колонок.

Аналогично, sns.boxplot(x='category', y='price', data=df) построит ящики с усами, автоматически вычислив медиану, квартили и потенциальные выбросы для каждой категории. Для парных отношений служит pairplot(), для матриц корреляций — heatmap(), для распределений — histplot() и kdeplot(). Все эти функции интегрированы с DataFrame Pandas: они принимают весь фрейм и имена колонок, а не сырые массивы NumPy.

Ещё одна ключевая особенность — дизайн по умолчанию. Seaborn поставляется с набором стилей (whitegrid, dark, ticks) и цветовых палитр (viridis, rocket, husl), оптимизированных для восприятия — контрастных, устойчивых к цветовой слепоте, эстетически сбалансированных. Благодаря этому даже простой вызов даёт график, пригодный для включения в презентацию — без дополнительной настройки шрифтов, толщин линий или отступов.

Однако важно понимать границы Seaborn — он не предназначен для построения нестандартных, уникальных визуализаций (например, карт, диаграмм Санки, 3D-поверхностей). Его сфера — стандартные статистические графики, но максимально удобно и максимально информативно. Для нестандартных задач возвращаются к Matplotlib или специализированным библиотекам.


Plotly

Там, где Matplotlib отвечает за статичные отчёты, а Seaborn — за исследовательский анализ, Plotly берёт на себя сценарии коммуникации и демонстрации. Его ключевая отличительная черта — интерактивность — увеличение области графика, наведение курсора для отображения точных значений, включение/отключение серий, анимация во времени — всё это работает "из коробки" в веб-браузере.

Plotly изначально разрабатывался как JavaScript-библиотека (Plotly.js), и её Python-обёртка (plotly.express, plotly.graph_objects) генерирует JSON-описание графика, которое затем рендерится клиентской стороной. Это даёт два важных преимущества. Во-первых, графики легко встраиваются в веб-приложения — через Dash (фреймворк от тех же авторов), Streamlit или Jupyter Notebook (с расширением plotly), сохраняя полную интерактивность. Во-вторых, рендеринг переносится на сторону пользователя, что снижает нагрузку на сервер при генерации сложных дашбордов.

Plotly Express — высокоуровневый API, похожий по духу на Seaborn: px.scatter(df, x='x', y='y', color='group', size='value') создаёт интерактивную диаграмму рассеяния с цветовой и размерной кодировкой за одну строку. При этом результат можно легко донастроить через объектную модель (update_layout(), update_traces()), добавить анимацию (animation_frame), построить 3D-графики (px.scatter_3d) или географические карты (px.choropleth).

Единственное ограничение — объём данных. Поскольку интерактивность требует передачи данных в браузер, чрезмерно большие наборы (десятки тысяч точек) могут замедлять работу. Для таких случаев применяется агрегация на стороне Python (через Pandas или Datashader), либо используется серверный рендеринг в статичные изображения.


Практикум по прикладным библиотекам анализа

Этот блок помогает расширить стек NumPy + Pandas + SciPy в прикладных задачах.

Pandas — типовые операции

Готовая подборка скриптов — DataFrame, фильтрация, groupby, очистка, merge и экспорт — в Pandas — типовые операции.

Matplotlib — быстрый график

Теория и справочник команд — Matplotlib — графики. Готовая подборка скриптов — линии, столбцы, scatter, подграфики, тепловые карты и экспорт — в примерах.

SymPy — уравнения и производные

SymPy дополняет NumPy там, где нужен точный символьный ответ — корни x² − 5x + 6 = 0, производная sin(x), система из двух уравнений, экспорт формулы в LaTeX. NumPy и SciPy считают по числам; SymPy — по буквам. Школьные и вузовские задачи с разбором каждой строки — SymPy — уравнения и производные. Формулы в PDF — LaTeX — формулы для отчётов; график после расчёта — Matplotlib — примеры. Численные методы без символов — Численные методы.


import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(0, 10, 100)
y = np.sin(x)

plt.plot(x, y, label="sin(x)")
plt.legend()
plt.grid(True)
plt.show()

Разбор:

  • np.linspace(0, 10, 100) создаёт 100 равномерных точек на отрезке.
  • np.sin(x) векторно вычисляет синус для всего массива x.
  • plt.plot(...) строит линию, label задаёт подпись в легенде.
  • legend() показывает подпись серии, grid(True) добавляет сетку.
  • show() открывает окно с графиком или рендерит его в ноутбуке.

Pillow — базовая обработка изображения

from PIL import Image

img = Image.open("input.jpg")
thumb = img.resize((320, 320))
thumb.save("thumb.jpg", quality=90)

Разбор:

  • Image.open(...) загружает изображение в объект Pillow.
  • resize((320, 320)) создаёт уменьшенную копию фиксированного размера.
  • save(..., quality=90) сохраняет JPEG с высоким качеством и разумным сжатием.

OpenCV — чтение и выделение контуров


import cv2

image = cv2.imread("frame.png")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, threshold1=50, threshold2=150)
cv2.imwrite("edges.png", edges)

Разбор:

  • imread(...) читает кадр как матрицу пикселей.
  • cvtColor(..., COLOR_BGR2GRAY) переводит изображение в оттенки серого.
  • Canny(...) выделяет границы объектов по перепадам яркости.
  • imwrite(...) сохраняет результат детекции контуров в файл.

TensorFlow и Keras — каркас модели


import tensorflow as tf

from tensorflow import keras

model = keras.Sequential(
[
keras.layers.Dense(64, activation="relu"),
keras.layers.Dense(10, activation="softmax"),
]
)
model.compile(optimizer="adam", loss="sparse_categorical_crossentropy")

Разбор:

  • Sequential([...]) собирает слои в простой линейный стек.
  • Первый Dense(64, activation="relu") строит скрытый слой на 64 нейрона.
  • Второй Dense(10, activation="softmax") формирует вероятности по 10 классам.
  • compile(...) задаёт оптимизатор и функцию потерь перед обучением.