Python для анализа данных: от автоматизации сбора до машинного обучения

Комплексный курс по освоению Python как основного инструмента аналитика. Программа охватывает полный цикл работы с данными: от парсинга и предобработки до статистического анализа и построения прогнозных моделей.

1. Основы Python: синтаксис и структуры данных для аналитика

Основы Python: синтаксис и структуры данных для аналитика

Представьте, что вам нужно проанализировать продажи в сети из пятисот магазинов, где данные поступают в разных форматах, с пропусками и опечатками. Делать это вручную в Excel — значит обречь себя на недели монотонного труда с высоким риском ошибки. Python превращает эту задачу в последовательность логических команд, которые выполняются за секунды. Но прежде чем строить прогнозы нейросетями или визуализировать тренды, необходимо освоить «анатомию» языка: как он хранит информацию, как принимает решения и как организует данные в структуры, пригодные для анализа.

Философия кода и переменные как контейнеры

В анализе данных мы редко работаем с одиночными значениями, но именно они являются строительными кирпичами любого датасета. В Python переменная — это не просто ячейка памяти, а ссылка на объект. Когда мы пишем sales = 1500.50, мы создаем объект типа «число с плавающей точкой» и вешаем на него ярлык sales.

Для аналитика критически важно понимать типы данных, так как от них зависит доступный инструментарий. Если вы случайно загрузите столбец с выручкой как текстовые строки, вы не сможете вычислить средний чек — Python выдаст ошибку или, что хуже, просто «склеит» строки.

  • Integer (int) — целые числа. Используются для счета объектов: количество транзакций, число проданных товаров, ID клиента.
  • Float (float) — числа с плавающей точкой. Это наши финансовые показатели, коэффициенты конверсии, вероятности. Важно помнить о точности: компьютер хранит дробные числа в двоичном виде, что иногда приводит к микроскопическим погрешностям вроде .
  • String (str) — строки. Текстовая информация: категории товаров, имена пользователей, комментарии.
  • Boolean (bool) — логический тип. Принимает значения True или False. Это фундамент для фильтрации данных.
  • Динамическая типизация Python позволяет менять тип переменной на лету, но в аналитике это часто становится ловушкой. Хорошим тоном считается явное преобразование типов, если есть сомнения в источнике данных.

    Управляющие конструкции: логика обработки данных

    Аналитика — это процесс постоянного выбора. «Если клиент совершил покупку более чем на 5000 руб., присвоить ему статус VIP», «Пока в списке есть необработанные файлы, продолжать загрузку». Эти сценарии реализуются через условные операторы и циклы.

    Условный оператор if-elif-else

    Логика ветвления позволяет сегментировать данные. В Python отступы (4 пробела) — это не вопрос эстетики, а синтаксическое требование. Код внутри блока выполняется только при соблюдении условия.

    Рассмотрим пример сегментации чека:

    Здесь важно соблюдать порядок: Python проверяет условия сверху вниз до первого совпадения. Если бы мы поставили условие > 5000 первым, то чек на 12 000 руб. попал бы в категорию "Standard", так как условие истинно, и Python не пошел бы проверять ветку elif.

    Циклы for и while

    Цикл for — основной инструмент аналитика для итерации (перебора) элементов. Мы используем его для обработки списков файлов, колонок в таблице или строк в отчете.

    Цикл while используется реже, обычно в задачах, где неизвестно точное количество итераций — например, при парсинге сайта, пока не закончатся страницы в пагинации. Однако с ним нужно быть осторожным: ошибка в условии может привести к бесконечному циклу, который «завесит» скрипт.

    Списки и кортежи: упорядоченные коллекции

    Когда данных становится много, нам нужны структуры для их группировки. Самая простая и часто используемая — список (list).

    Списки (list)

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

    Основные операции со списками:

  • Slicing (срезы): `. Позволяет вырезать часть данных. Например, prices[:3] вернет первые три цены.
  • Методы: .append() добавляет элемент в конец, .extend() объединяет списки, .sort() упорядочивает данные.
  • Важный нюанс: списки в Python могут содержать объекты разных типов, но для эффективного анализа данных (особенно в библиотеках NumPy и Pandas, которые мы изучим позже) рекомендуется хранить в одной структуре данные одного типа.

    Кортежи (tuple)

    Кортеж — это неизменяемый список. Создается в круглых скобках (1, 2, 3). Зачем он нужен аналитику?
  • Безопасность: если данные не должны меняться (например, координаты GPS или настройки подключения к базе данных), кортеж гарантирует их целостность.
  • Скорость: кортежи работают быстрее списков и занимают меньше памяти.
  • Ключи словарей: кортеж может быть ключом в словаре, а список — нет.
  • Словари: ключ к структурированным данным

    Если список — это просто мешок с пронумерованными вещами, то словарь (dict) — это картотека. Данные в нем хранятся в виде пар «ключ: значение». Это идеальная структура для представления одной записи из базы данных или JSON-ответа от API.

    Преимущество словаря в скорости доступа. Чтобы найти цену товара в списке из миллиона элементов, Python придется просмотреть их все (в худшем случае). В словаре поиск по ключу происходит мгновенно, независимо от размера структуры.

    Для аналитика словари незаменимы при:

  • Создании справочников (например, замена кодов регионов на их названия).
  • Агрегации данных вручную (подсчет частоты встречаемости слов или категорий).
  • Хранении конфигураций моделей машинного обучения.
  • Множества: очистка от дублей

    Множество (set) — это неупорядоченная коллекция уникальных элементов. Если вы загрузили список ID транзакций и хотите узнать, сколько уникальных клиентов совершили покупки, просто оберните список в set().

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

    Функции: автоматизация и переиспользование кода

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

    Функция определяется ключевым словом def. Она принимает аргументы и возвращает результат через return.

    В программировании для анализа данных функции играют роль «мини-конвейеров». Мы можем написать функцию для обработки одной строки данных, а затем применить ее к миллиону строк в таблице Pandas.

    Области видимости и чистые функции

    Для аналитика важно писать «чистые» функции — те, результат которых зависит только от входных аргументов, и которые не меняют глобальные переменные. Это делает код предсказуемым и облегчает отладку. Переменная, созданная внутри функции, «умирает» после завершения ее работы — это локальная область видимости.

    Обработка исключений: когда данные «ломаются»

    Реальные данные грязные. В колонке с числами может внезапно встретиться строка "N/A", а при делении выручки на количество заказов может возникнуть деление на ноль, если заказов не было. Без обработки ошибок ваш скрипт остановится на середине долгого процесса.

    Конструкция try-except позволяет программе «выжить» при столкновении с ошибкой.

    В аналитике это критично при парсинге сайтов: если один из тысячи товаров на сайте имеет другую структуру верстки, try-except позволит пропустить его и собрать остальные 999, вместо того чтобы прервать работу всей программы.

    Списковые включения (List Comprehensions)

    Это «синтаксический сахар» Python, который аналитики используют постоянно. Он позволяет создавать новые списки на основе существующих в одну строку.

    Предположим, у нас есть список цен в долларах, и мы хотим перевести их в рубли по курсу 90:

    Такой подход не только короче, но и зачастую быстрее работает. В него также можно встраивать условия: [p * 90 for p in usd_prices if p > 15] — пересчитать только те цены, что выше 15 долларов.

    Работа с библиотеками и импорт модулей

    Python — это «язык с батарейками в комплекте», но его истинная мощь для аналитика кроется во внешних библиотеках. Чтобы использовать инструменты, их нужно импортировать.

    Существует несколько способов импорта:

  • import math — импортирует весь модуль. Доступ к функциям через точку: math.sqrt(16).
  • from datetime import datetime — импортирует конкретный класс или функцию.
  • import pandas as pd — импорт с псевдонимом. Это стандарт индустрии: почти все аналитики сокращают Pandas до pd, а NumPy до np.
  • Понимание того, как устроены пакеты и модули, поможет вам эффективно использовать документацию. Если вы видите в коде plt.plot(), вы сразу понимаете, что используется библиотека Matplotlib, импортированная как plt.

    Нюансы работы с памятью и копированием

    При работе с большими объемами данных (например, списками на миллионы элементов) важно понимать разницу между поверхностным и глубоким копированием. В Python присваивание list_b = list_a не создает копию данных. Оно создает вторую ссылку на тот же самый список. Если вы измените list_b, изменится и list_a.

    Для создания независимой копии используется метод .copy() или модуль copy. В анализе данных это часто встречается при создании промежуточных срезов таблиц: если вы не сделаете копию, изменения в отфильтрованных данных могут неожиданно «просочиться» в исходный датасет.

    Практическое применение: от синтаксиса к аналитике

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

    В этом коротком примере задействованы почти все основы:

  • Список словарей как модель данных.
  • List comprehension для извлечения цен.
  • Встроенная функция sum()` для агрегации.
  • Set comprehension (создание множества в одну строку) для получения уникальных категорий.
  • F-строки для форматированного вывода.
  • Замыкание основ

    Освоение синтаксиса Python — это не заучивание команд, а развитие навыка декомпозиции задачи. Любой сложный отчет можно разбить на элементарные операции: получить данные (списки/словари), проверить условия (if/else), повторить действия для каждой строки (циклы), очистить от дублей (множества) и упаковать логику в функции.

    Эти базовые структуры данных являются фундаментом для библиотек NumPy и Pandas. Массивы в NumPy — это оптимизированные списки, а DataFrame в Pandas можно представить как словарь, где ключи — это названия колонок, а значения — списки данных. Понимая, как Python работает «под капотом», вы сможете писать эффективный код, который не только выдает верный результат, но и легко читается коллегами-аналитиками.

    2. Автоматизация сбора данных и парсинг веб-сайтов с BeautifulSoup

    Автоматизация сбора данных и парсинг веб-сайтов с BeautifulSoup

    Каждое утро аналитик крупного маркетплейса начинает рабочий день не с кофе, а с проверки цен конкурентов. Если делать это вручную, открывая сотни вкладок, рабочий день закончится, так и не начавшись. В мире Big Data информация редко поставляется в виде аккуратных CSV-файлов или готовых баз данных. Чаще она «размазана» по миллионам веб-страниц, скрыта за тегами HTML и перемешана с рекламными баннерами. Навык написания скриптов, которые самостоятельно заходят на сайты, находят нужные цифры и упаковывают их в таблицу, превращает аналитика из пассивного потребителя данных в активного исследователя.

    Анатомия веб-запроса и протокол HTTP

    Прежде чем извлекать данные, их нужно получить. Когда мы вводим адрес в браузере, происходит сложный диалог между нашим компьютером (клиентом) и удаленным сервером. В Python роль такого клиента чаще всего берет на себя библиотека requests.

    Работа с любым сайтом начинается с отправки HTTP-запроса. Самый распространенный тип запроса — GET, который буквально означает: «Дай мне содержимое этой страницы». В ответ сервер присылает код состояния (status code). Если вы видите код 200, значит, все прошло успешно. Если 404 — страница не найдена, а 403 означает, что сервер распознал в вас робота и закрыл доступ.

    Для аналитика критически важно понимать, что сервер видит не человека, а набор заголовков (headers). Один из важнейших заголовков — User-Agent. Он сообщает серверу, какой браузер и какая операционная система используются. По умолчанию requests честно признается: «Я — библиотека Python-requests». Многие сайты блокируют такие запросы, чтобы защититься от перегрузки ботами. Поэтому первым шагом автоматизации всегда становится «маскировка» — подмена User-Agent на строку, имитирующую реальный браузер вроде Chrome или Firefox.

    HTML как древовидная структура

    Получив ответ от сервера, мы видим «кашу» из символов — это HTML-код. HTML (HyperText Markup Language) не является языком программирования, это язык разметки. Он структурирует контент с помощью тегов. Для парсинга нам важно воспринимать HTML не как текст, а как иерархическое дерево (DOM — Document Object Model).

    Представьте дерево: у него есть корень (тег <html>), от которого отходят ветви-родители (<body>, <head>), а внутри них находятся «листья» — теги с контентом (<h1> для заголовков, <p> для абзацев, <a> для ссылок). Библиотека BeautifulSoup как раз и нужна для того, чтобы превратить плоский текст в это дерево, по которому удобно перемещаться.

    Основные элементы, на которые мы опираемся при поиске данных:

  • Теги: определяют тип данных (таблица, заголовок, список).
  • Атрибуты: уточняют свойства тега. Самые важные для нас — class и id. Разработчики сайтов используют их для оформления, а мы — как уникальные маркеры для поиска.
  • Текст: то, что находится внутри тегов — именно те цены, названия товаров и даты, ради которых затевается парсинг.
  • Первые шаги с BeautifulSoup: поиск и извлечение

    После того как мы получили объект «супа» (экземпляр класса BeautifulSoup), у нас появляются два мощных инструмента: методы .find() и .find_all().

    Метод .find() возвращает первое совпадение. Это удобно, если на странице есть только один главный заголовок или одна цена, которую нужно забрать. Если же нам нужен список всех товаров, мы используем .find_all(), который возвращает итерируемый объект (список) со всеми найденными элементами.

    Рассмотрим нюанс с атрибутом class. В Python слово class зарезервировано для создания классов, поэтому в BeautifulSoup при поиске по классу мы используем class_ (с нижним подчеркиванием).

    В этом примере метод .strip() крайне важен. HTML-код часто содержит лишние пробелы, символы переноса строки и табуляцию. Очистка данных начинается уже на этапе их извлечения.

    Навигация по дереву: родители, дети и соседи

    Иногда данные не имеют уникальных классов. Например, на сайте госзакупок нужная цифра может лежать в обычном теге <td> внутри таблицы, где таких тегов сотни, и ни у одного нет класса. В таких случаях мы используем относительную навигацию.

    Мы можем найти ячейку с текстом «Итого», а затем попросить BeautifulSoup найти «следующего соседа» (next sibling). Это позволяет перемещаться по структуре документа в любом направлении:

  • .parent — подняться на уровень выше.
  • .children — спуститься к вложенным элементам.
  • .find_next_sibling() — перейти к следующему элементу на том же уровне.
  • Это напоминает ориентирование на местности: «Найди дерево с красной лентой, и нужный клад будет во втором кусте справа от него».

    Работа со сложными структурами: ссылки и изображения

    Данные — это не только текст. Часто аналитикам нужны ссылки на страницы товаров или URL-адреса изображений для обучения нейросетей. Эти данные хранятся не внутри тега, а в его атрибутах.

    Для тега <a> (ссылка) адрес хранится в атрибуте href. Для тега <img> — в атрибуте src. Доступ к ним в BeautifulSoup реализован через квадратные скобки, как в обычных Python-словарях, которые мы изучили ранее.

    Важный момент: ссылки на сайтах бывают относительными (например, /product/123) и абсолютными (с указанием домена). При автоматизации сбора данных необходимо проверять формат ссылки и, если нужно, склеивать её с базовым адресом сайта, используя библиотеку urllib.parse.

    Обработка пагинации: сбор данных с нескольких страниц

    Редко когда все нужные данные умещаются на одной странице. Обычно они разбиты на части (пагинация). С точки зрения кода, пагинация — это цикл. Нам нужно понять, как меняется URL при переходе со страницы на страницу.

    Чаще всего это выглядит как параметр в строке запроса: ?page=1, ?page=2 и так далее. В таком случае мы оборачиваем наш парсер в цикл for, который подставляет номер страницы в URL.

    Однако здесь кроется ловушка. Если мы отправим 100 запросов за одну секунду, сервер сочтет это за DDoS-атаку и заблокирует наш IP-адрес. Профессиональный парсинг требует «человечности». Мы должны использовать библиотеку time и функцию time.sleep(), чтобы делать паузы между запросами (от 1 до 5 секунд). Это снижает нагрузку на сервер и делает наше поведение более похожим на действия реального пользователя.

    Этические и юридические аспекты автоматизации

    Парсинг — это мощный инструмент, но он требует ответственности. Прежде чем запускать скрипт, необходимо проверить файл robots.txt, который находится в корне сайта (например, example.com/robots.txt). В нем владельцы ресурсов указывают, какие разделы запрещено посещать роботам.

    Существует понятие «вежливого парсинга» (polite scraping):

  • Не делайте запросы слишком часто.
  • Не собирайте персональные данные пользователей без разрешения.
  • Если у сайта есть официальный API — используйте его вместо парсинга. API работает быстрее, стабильнее и легальнее.
  • С юридической точки зрения, сбор общедоступной информации (цены, описания товаров) обычно допустим, но использование её в коммерческих целях для создания сайта-клона может привести к судебным искам. Аналитик всегда должен помнить: мы собираем данные для исследования, а не для кражи контента.

    Обработка ошибок и «грязного» HTML

    Интернет нестабилен. Сайт может временно «лечь», структура страницы может измениться в любой момент, или у одного из товаров может просто отсутствовать цена. Если ваш скрипт не готов к таким ситуациям, он упадет на середине процесса, и вы потеряете собранные данные.

    Здесь на помощь приходит конструкция try-except, изученная в первой главе. Мы должны оборачивать в нее каждый потенциально опасный участок: сетевой запрос и поиск конкретных тегов.

    Также полезно проверять наличие элемента перед тем, как вызывать у него метод .text. Если item.find("span") вернет None (элемент не найден), попытка обратиться к .text вызовет AttributeError. Хорошим тоном считается использование условий: price = price_tag.text if price_tag else "0".

    Проблема динамического контента

    BeautifulSoup и requests отлично справляются со статическими страницами, где весь контент сразу прописан в HTML-коде. Однако современный веб все чаще строится на JavaScript (React, Vue, Angular). На таких сайтах при загрузке страницы вы видите только пустой каркас и индикатор загрузки, а сами данные подгружаются позже.

    Если вы попробуете спарсить такой сайт через BeautifulSoup, вы получите пустые теги. Для решения этой проблемы существуют другие инструменты, такие как Selenium или Playwright, которые запускают настоящий браузер и ждут выполнения всех скриптов. Тем не менее, часто можно найти «лазейку»: изучить вкладку Network в инструментах разработчика браузера и найти прямой запрос к API сайта, который возвращает данные в чистом формате JSON. Это гораздо эффективнее, чем имитировать работу браузера.

    Хранение собранных данных

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

    Мы можем записывать каждую найденную строку товара в файл прямо в процессе парсинга. Это гарантирует, что даже если скрипт прервется на 500-й странице, данные первых 499 страниц останутся сохраненными.

    В будущем мы научимся передавать эти списки словарей напрямую в Pandas DataFrame, но понимание работы с файлами напрямую закладывает фундамент для работы с большими объемами данных, которые не всегда помещаются в память.

    Масштабирование: от одного скрипта к системе

    Когда задач по сбору становится много, возникает необходимость в автоматизации запуска. Скрипты для парсинга часто настраивают на выполнение по расписанию (например, с помощью планировщика cron на Linux или Task Scheduler на Windows).

    Для действительно масштабных проектов, где нужно обходить миллионы страниц, используются фреймворки вроде Scrapy. Они позволяют распараллеливать запросы, автоматически обрабатывать куки, следовать по ссылкам и сохранять данные в базы. Но для 90% задач аналитика связки requests + BeautifulSoup более чем достаточно. Она проста в отладке, не требует сложной настройки и позволяет быстро получить результат.

    Умение парсить сайты превращает интернет в гигантскую структурированную базу данных. Главное — помнить, что за каждым сайтом стоит труд разработчиков и ресурсы серверов. Уважительное отношение к чужой инфраструктуре и грамотный код — признаки профессионального аналитика. В следующих главах мы научимся обрабатывать те массивы информации, которые сегодня научились собирать, превращая «сырой» HTML-текст в ценные инсайты для бизнеса.