Анализ данных - pandas, NumPy, SciPy
Анализ данных и научные вычисления
Программирование на Python давно вышло за пределы сценариев автоматизации и веб-разработки, заняв ведущие позиции в области обработки информации, моделирования и принятия решений на основе данных. Эта трансформация стала возможной благодаря формированию зрелой экосистемы библиотек, объединённых общей философией эффективности, ясности и научной строгости. Среди них особое место занимают три кита — NumPy — фундамент для численных операций, Pandas — инструментарий для структурированного анализа, и Matplotlib/Seaborn/Plotly — среда визуализации. Вместе они образуют каркас, на котором строятся как академические исследования, так и промышленные решения — от прогнозирования спроса в ритейле до обработки сигналов в телемедицине.
Начнём с основания — с NumPy. Теория массивов, dtype и линейная алгебра в коде — NumPy — массивы, векторы и матрицы; готовые скрипты с разбором каждой строки — Lab 1129. Математика векторов и матриц — 342, 343.
Если воспринимать этот раздел как карту, то логика пути такая:
- NumPy — быстрые вычисления — 337 + Lab 1129;
- Pandas превращает сырые данные в табличную рабочую модель;
- визуализация помогает увидеть закономерности и объяснить выводы другим.
Такой порядок изучения наиболее практичен для начинающего разработчика.
Series (одна колонка) → DataFrame (таблица) → 331 — merge, pivot, временные ряды → 428–427 — EDA и очистка → Lab 1113 → Lab 1148 — продажи → sklearn → Lab 1157 — Titanic.
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 — типовые операции. Те же задачи в Excel — Excel и 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.
Минимальный практический маршрут
Ниже последовательность, которая обычно даёт быстрый результат в учебном или рабочем проекте:
- Загрузить один CSV в Pandas и проверить
df.info()/df.head()(команды — Pandas — типовые операции при анализе данных, примеры с разбором, очистка — Очистка и подготовка данных в Pandas). - Убрать явные пропуски и дубликаты.
- Построить 2-3 базовых графика распределения и тренда.
- Сформировать сводную таблицу с ключевыми агрегатами.
- Если нужна предиктивная модель — начать с 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(...)задаёт оптимизатор и функцию потерь перед обучением.