Pandas на Python: От чтения CSV до сложной аналитики за 1 статью. Data Engineering.. Data Engineering. pandas.. Data Engineering. pandas. pandas dataframe.. Data Engineering. pandas. pandas dataframe. pandas merge.. Data Engineering. pandas. pandas dataframe. pandas merge. python.. Data Engineering. pandas. pandas dataframe. pandas merge. python. python для начинающих.. Data Engineering. pandas. pandas dataframe. pandas merge. python. python для начинающих. python3.. Data Engineering. pandas. pandas dataframe. pandas merge. python. python для начинающих. python3. Программирование.. Data Engineering. pandas. pandas dataframe. pandas merge. python. python для начинающих. python3. Программирование. Учебный процесс в IT.

1. Введение и быстрый старт: Excel на максималках

Давайте начистоту. Если вы когда-нибудь пытались анализировать табличные данные с помощью стандартных списков и словарей Питона, вы знаете, какая это боль. Циклы внутри циклов, куча проверок на пустоту, простыни кода ради простейшей группировки…

А если вы пробовали открыть CSV-файл на пару-тройку миллионов строк в обычном Excel — ну, вы наверняка помните этот зависший белый экран и звук взлетающего кулера.

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

В этой статье я собрал самую выжимку — базовый пайплайн, которого хватит для старта. А если после прочтения вам захочется погрузиться в тему серьезнее, порешать задачки и набить руку на реальных датасетах, заходите на мой бесплатный курс «Pandas для анализа данных: Полный курс» на Stepik. Там мы разбираем всё: от основ до продвинутых фишек.

Установка и импорт

Хватит лирики, давайте к делу. Если Pandas у вас еще не установлен (хотя в сборках вроде Anaconda он идет из коробки), открываем терминал и пишем классическое:

pip install pandas
Pandas на Python: От чтения CSV до сложной аналитики за 1 статью - 1

Готово. Теперь открываем ваш любимый редактор или Jupyter Notebook.

В мире Python есть негласное, но абсолютно железобетонное правило: никто не пишет просто import pandas. Все разработчики в мире договорились использовать сокращение (алиас) pd. Считайте это невидимым контрактом, который вы подписываете при входе в анализ данных:

import pandas as pd
Pandas на Python: От чтения CSV до сложной аналитики за 1 статью - 2

2. Основы: Series и DataFrame (Из чего состоят таблицы)

Вся магия Pandas строится на двух базовых «детальках Лего». Если вы поймете, как они работают, всё остальное пойдет как по маслу.

Series (Серия): колонка

Представьте себе обычный питоновский список: [10, 20, 30]. А теперь представьте, что к каждому элементу этого списка приклеили этикетку с адресом. Это и есть Series — одномерный массив данных. По сути, это просто одна колонка из таблицы.

Главное отличие Series от обычного списка — наличие индекса (тех самых этикеток). По умолчанию это просто порядковые номера (0, 1, 2…), но вы можете сделать индексами хоть даты, хоть имена, хоть буквы алфавита.

DataFrame (Датафрейм): царь-таблица

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

DataFrame — это двумерная таблица, с которой вы и будете работать 99% времени. Это ваш рабочий лист Excel, таблица из SQL-базы или загруженный CSV-файл.

Чтобы не быть голословными, давайте создадим DataFrame прямо сейчас. В реальной жизни вы редко будете набивать данные руками (для этого есть чтение файлов, о котором в следующем пункте), но для тестов и понимания сути проще всего собрать датафрейм из обычного словаря (dict).

Давайте опишем небольшую IT-команду:

import pandas as pd

# Обычный питоновский словарь со списками внутри
team_data = {
    'Имя': ['Алексей', 'Мария', 'Иван', 'Елена'],
    'Роль': ['Python Dev', 'Data Analyst', 'DevOps', 'Product Manager'],
    'Зарплата_руб': [250000, 180000, 220000, 300000],
    'Кофе_чашек_в_день': [4, 2, 5, 1]
}

# Превращаем тыкву (словарь) в карету (DataFrame)
df = pd.DataFrame(team_data)

# Посмотрим, что получилось
print(df)
Pandas на Python: От чтения CSV до сложной аналитики за 1 статью - 3

Вывод на экран будет выглядеть так:

       Имя             Роль  Зарплата_руб  Кофе_чашек_в_день
0  Алексей       Python Dev        250000                  4
1    Мария     Data Analyst        180000                  2
2     Иван           DevOps        220000                  5
3    Елена  Product Manager        300000                  1
Pandas на Python: От чтения CSV до сложной аналитики за 1 статью - 4

Разбираем архитектуру

Посмотрите на вывод выше. В датафрейме есть три важнейшие сущности, которые нужно знать в лицо:

  1. Данные (Data): Сама таблицы — имена, цифры, роли.

  2. Колонки (Columns): Заголовки сверху. В нашем случае это 'Имя', 'Роль', .... Колонки — это горизонтальный адрес данных.

  3. Индекс (Index): Обратите внимание на цифры 0, 1, 2, 3 с левого края. Мы их не создавали, Pandas добавил их сам. Это номера строк — вертикальный адрес данных.

Почему я так акцентирую на этом внимание? Потому что вся навигация по таблице, фильтрация и поиск значений в Pandas строится на пересечении Колонок и Индексов. Это как игра в морской бой: чтобы найти нужную ячейку, вам нужно назвать ряд и колонку.

3. Загрузка и выгрузка данных (I/O)

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

Чтение данных: как втянуть файл в память

Самый популярный формат обмена данными — это старый добрый CSV (Comma-Separated Values). Чтобы загрузить его в Pandas, нужна ровно одна строчка кода. Эту команду в мире, наверное, запускают миллион раз в секунду:

df = pd.read_csv('my_data.csv')
Pandas на Python: От чтения CSV до сложной аналитики за 1 статью - 5

Всё! Датафрейм готов. Но есть нюанс. В идеальном мире все CSV-файлы разделены запятыми. В реальном мире кто-то выгрузил файл из 1С, кто-то из русской версии Excel, и вместо запятой там точка с запятой (;), а то и вообще табуляция. Если вы просто сделаете read_csv, Pandas свалит всё в одну нечитаемую колонку.

Поэтому нужно знать два главных параметра:

  • sep (от слова separator). Явно указываем разделитель. Если у вас русская экселька, пишем: pd.read_csv('data.csv', sep=';').

  • index_col. Часто бывает, что в первой колонке вашего файла уже лежат какие-нибудь айдишники (например, user_id). Если файл загрузить как есть, Pandas создаст свой индекс (0, 1, 2…), а user_id сделает обычной колонкой. Чтобы сказать библиотеке: «Эй, используй первую колонку как индекс!», пишем: pd.read_csv('data.csv', index_col=0).

А как же Excel?

Если вам прислали файл .xlsx, не беда. Метод называется ожидаемо:

df = pd.read_excel('report.xlsx', sheet_name='Sheet1')
Pandas на Python: От чтения CSV до сложной аналитики за 1 статью - 6

Маленький совет: чтобы read_excel работал, у вас должна быть установлена библиотека openpyxl (ставится так же через pip). Параметр sheet_name позволяет указать имя конкретной вкладки, если их в файле несколько.

Сохранение результатов: Золотое правило index=False

Допустим, вы загрузили данные, почистили их, посчитали всё, что нужно, и теперь хотите отправить результат коллеге. Нам нужно выгрузить датафрейм обратно в файл. Делается это методами to_csv() или to_excel().

df.to_csv('clean_data.csv', index=False)
Pandas на Python: От чтения CSV до сложной аналитики за 1 статью - 7

Стоп. Почему index=False?
Запомните этот параметр, он спасет вам кучу нервов. Помните те самые номера строк (0, 1, 2, 3), которые Pandas автоматически приклеивает слева? Если вы не напишете index=False, Pandas сохранит эти цифры в файл как новую безымянную колонку.

Когда ваш коллега завтра прочитает этот файл, Pandas добавит еще один индекс. У него появится колонка Unnamed: 0. Если он сохранит файл и пришлет вам, у вас будет Unnamed: 0.1… В мире дата-сайенса это классический мем. Так что просто возьмите в привычку: сохраняете данные — отключайте экспорт индекса (если только он не несет в себе какой-то полезной информации вроде дат).

4. Знакомство с данными (Первичный осмотр)

Итак, вы загрузили файл. Отлично.

Первое негласное правило любого аналитика или дата-сайентиста: сначала посмотри на данные глазами. Вдруг там съехали колонки? Вдруг вместо чисел пришел текст? А может, половина таблицы вообще пустая? Чтобы не получить мусор на выходе, в Pandas есть три метода для быстрой и элегантной разведки (так называемый EDA — Exploratory Data Analysis).

Методы .head() и .tail(): Посмотреть глазками

Как мы привыкли делать в Excel? Открываем файл и начинаем скроллить. В Pandas выводить на экран датафрейм из миллиона строк бессмысленно (он всё равно покажет только начало и конец, скрыв середину за многоточием).

Чтобы быстро провести sanity check (проверку на адекватность), мы просим Pandas показать нам “голову” (начало) или “хвост” (конец) таблицы:

# Смотрим первые 5 строк (по умолчанию)
df.head()

# Смотрим последние 3 строки (можно передать любое число)
df.tail(3)
Pandas на Python: От чтения CSV до сложной аналитики за 1 статью - 8

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

Метод .info(): Рентген вашего датафрейма

Если .head() — это беглый визуальный осмотр пациента, то .info() — это глубокий рентген. Это абсолютно незаменимый метод, который нужно вызывать каждый раз, когда вы видите датасет впервые.

df.info()
Pandas на Python: От чтения CSV до сложной аналитики за 1 статью - 9

Вывод этого метода не очень красивый, это просто текст, но в нем кроется тонна ответов:

  1. Размер таблицы: сколько всего строк (Index) и колонок (Columns).

  2. Типы данных (Dtype): Pandas автоматически пытается угадать тип данных в колонке. int64 — целые числа, float64 — числа с точкой. Если вы видите object — обычно это текст. Сразу лайфхак: если вы ждали колонку с ценой в числах, а .info() говорит, что там object — значит, в данные затесался мусор (например, кто-то написал «1000 руб» буквами). Математика на этой колонке сломается, ее придется чистить.

  3. Оценка масштаба катастрофы с пропусками: Обратите внимание на столбик Non-Null Count. Если всего в таблице 1000 строк, а в колонке “Возраст” стоит 850 non-null — значит, у 150 человек возраст не указан (там лежат значения NaN). Морально готовьтесь с этим разбираться.

  4. Потребление памяти (Memory usage): Сколько мегабайт ваш датафрейм отъедает в оперативке.

Метод .describe(): Статистика для ленивых

Допустим, с типами данных всё окей, числа распознались как числа. Теперь хочется понять масштаб значений. Какая средняя зарплата в датасете? Кто самый молодой? Какой разброс цен?

Вместо того чтобы писать руками формулы для каждой колонки, мы используем “волшебную кнопку”:

df.describe()
Pandas на Python: От чтения CSV до сложной аналитики за 1 статью - 10

Pandas сам пробежится по таблице, найдет все числовые колонки (текстовые он проигнорирует) и выдаст по ним готовую статистическую сводку:

  • count — количество заполненных (непустых) ячеек.

  • mean — среднее арифметическое.

  • std — стандартное отклонение (показывает, насколько сильно данные “размазаны” вокруг среднего).

  • min и max — минимумы и максимумы (сразу видно аномалии: например, если max возраст равен 999 — кто-то ошибся при вводе).

  • 25%, 50%, 75% — квартили. Кстати, 50% — это медиана. Опытные аналитики всегда смотрят на нее, а не на среднее (mean), чтобы один Билл Гейтс не исказил статистику по доходам всего бара.

Всего три короткие строчки кода — а вы уже знаете о своих данных больше, чем человек, который собирал этот файл!

5. Индексация и фильтрация (Как достать то, что нужно)

Итак, мы посмотрели на данные в целом. Но в реальности вам редко нужна вся таблица целиком. Обычно датасеты содержат десятки колонок, а для отчета вам нужны только три. Или вам нужно вытащить данные только по одному конкретному отделу.

В Pandas есть несколько способов «нарезать» таблицу. На первых порах синтаксис может показаться непривычным, но к нему быстро привыкаешь.

Выбор колонок: Одинарные или двойные скобки?

Чтобы достать из датафрейма одну колонку, мы обращаемся к ней по имени в квадратных скобках, прямо как по ключу в словаре:

names = df['Имя']
Pandas на Python: От чтения CSV до сложной аналитики за 1 статью - 11

На выходе вы получите тот самый одномерный объект Series.

Но что, если нам нужны две колонки? Имя и Зарплата? И вот тут 99% новичков совершают свою первую ошибку, пытаясь написать df['Имя', 'Зарплата']. Pandas выдаст злющую ошибку.

Правильно делать так: вы передаете внутрь квадратных скобок список нужных колонок. То есть появляются двойные скобки:

# Обратите внимание на [[ ]]
subset = df[['Имя', 'Зарплата_руб']]
Pandas на Python: От чтения CSV до сложной аналитики за 1 статью - 12

Вуаля! На выходе вы получили новый, аккуратненький DataFrame только с двумя колонками. Запомните: одинарные скобки — для одной колонки (вернут Series), двойные скобки — для нескольких (вернут DataFrame).

По строкам: Вечная путаница loc и iloc

Если с колонками всё просто, то выбор конкретных строк — это главная драма для тех, кто только изучает Pandas. Есть два метода, которые делают вроде бы одно и то же, но по-разному. Давайте раз и навсегда закроем этот вопрос.

  • iloc (integer location) — поиск по порядковому номеру.
    Представьте, что это слепой робот. Ему всё равно, как называются ваши строки (какой у них индекс). Он понимает только координаты: «дай мне первую строку» или «дай мне строки с 10-й по 20-ю».

    # Получить самую первую строку в таблице (индекс 0)
    df.iloc[0] 
    
    # Получить первые 5 строк (работают обычные питоновские срезы!)
    df.iloc[0:5] 
    
    Pandas на Python: От чтения CSV до сложной аналитики за 1 статью - 13
  • loc (location) — поиск по имени (метке).
    А это уже умный курьер, который ищет по адресу. Он смотрит на ваш Индекс (те самые названия строк слева). Если ваш индекс — это даты, вы ищете по датам. Если имена — по именам.

    # Допустим, мы сделали колонку 'Имя' индексом таблицы
    df.set_index('Имя', inplace=True)
    
    # Теперь мы можем достать данные конкретного человека по метке!
    df.loc['Алексей'] 
    
    Pandas на Python: От чтения CSV до сложной аналитики за 1 статью - 14

Краткое правило: iloc — это всегда математическая позиция (0, 1, 2…). loc — это то, что реально написано в Индексе.

Булева фильтрация: Магия условий

Доставать строки по номерам — это скучно. Самая частая задача звучит так: «А выведи-ка мне всех разработчиков старше 18 лет, у которых зарплата больше 200 тысяч». В SQL для этого есть WHERE. В Excel — фильтры по колонкам. В Pandas есть Boolean Indexing (булева фильтрация).

Выглядит эта магия так:

# Хотим найти тех, кто пьет больше 3 чашек кофе
hard_workers = df[df['Кофе_чашек_в_день'] > 3]
Pandas на Python: От чтения CSV до сложной аналитики за 1 статью - 15

Почему конструкция выглядит как масло масляное (df[df...])?
Всё логично:

  1. Внутренняя часть df['Кофе_чашек_в_день'] > 3 пробегается по каждой строке и возвращает список ответов: [True, False, True, False].

  2. Внешние скобки df[...] применяют этот список к таблице, оставляя только те строки, где выпало True.

Сложные условия

А если условий несколько? Мы склеиваем их с помощью логических операторов & (И) или | (ИЛИ).

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

# Ищем богатых Питонистов
rich_pythons = df[
    (df['Роль'] == 'Python Dev') & 
    (df['Зарплата_руб'] > 200000)
]
Pandas на Python: От чтения CSV до сложной аналитики за 1 статью - 16

Вот так, без единого цикла for и десятков if/else, мы в одну строчку отфильтровали огромную таблицу по сложным критериям. Работает моментально даже на миллионах строк.

6. Трансформация и очистка данных (Уборка перед анализом)

Реальные данные никогда не бывают идеальными. Они приходят с опечатками, пустыми ячейками, дубликатами и странными названиями колонок. Если вы скормите такой “грязный” датасет алгоритму машинного обучения или попытаетесь построить красивый отчет — получите мусор на выходе.

Поэтому 80% времени аналитика занимает именно очистка данных (Data Cleaning). В Pandas для этого есть свой арсенал швабр и пылесосов.

Пропуски (NaN): Найти и обезвредить

Самая частая боль — пустые ячейки. В базе данных это NULL, а в Pandas — загадочный NaN (Not a Number). Любая математическая операция с NaN (например, попытка сложить зарплату и NaN) вернет NaN. Это как черная дыра, которая съедает ваши расчеты.

Что с ними делать?

  • Шаг 1: Найти.
    Сначала нужно понять масштаб бедствия. Метод isna() возвращает таблицу такого же размера, где вместо значений стоят True (если пусто) или False. Но смотреть на огромную таблицу из True/False бессмысленно. Поэтому мы сразу просим посчитать сумму пропусков в каждой колонке:

    # Выдаст количество NaN в каждой колонке
    df.isna().sum() 
    
    Pandas на Python: От чтения CSV до сложной аналитики за 1 статью - 17
  • Шаг 2: Принять решение (Удалить или Заполнить?).
    Если пропусков мало (например, 5 строк из 10 000), проще всего их удалить. Метод dropna() по умолчанию удалит любую строку, в которой есть хотя бы один NaN.

    # Жестко удаляем все строки с пропусками
    clean_df = df.dropna()
    
    Pandas на Python: От чтения CSV до сложной аналитики за 1 статью - 18

    Но если у вас пустая колонка “Второй телефон” у половины базы, удалять эти строки нельзя — вы потеряете кучу ценных клиентов! В этом случае пропуски лучше заполнить чем-то нейтральным: нулями, словом “Не указан” или, например, средней зарплатой по отделу.

    # Заполняем пропуски в колонке 'Зарплата' нулями
    df['Зарплата_руб'] = df['Зарплата_руб'].fillna(0)
    
    # Или словом 'Unknown' для текстовых колонок
    df['Роль'] = df['Роль'].fillna('Unknown')
    
    Pandas на Python: От чтения CSV до сложной аналитики за 1 статью - 19

Создание новых колонок: Векторизация в действии

Часто нам нужно посчитать что-то новое на основе того, что уже есть. Например, перевести зарплату из рублей в доллары или посчитать общую выручку (цена × количество).

Если вы пришли из обычного Питона, ваша рука инстинктивно потянется написать цикл for, который побежит по строкам. Бейте себя по рукам! В Pandas циклы работают возмутительно медленно.

Вместо этого мы используем магию векторизации — применяем математику сразу ко всей колонке разом:

# Допустим, курс доллара 90. 
# Pandas сам разделит КАЖДОЕ значение в колонке на 90 за долю секунды.
df['Зарплата_USD'] = df['Зарплата_руб'] / 90

# Или перемножим две колонки между собой (строка за строкой)
df['total_price'] = df['price'] * df['qty']
Pandas на Python: От чтения CSV до сложной аналитики за 1 статью - 20

Синтаксис до смешного прост: вы просто объявляете имя новой колонки в квадратных скобках (как новый ключ в словаре) и присваиваете ей результат вычислений.

Наведение красоты: Переименование и Дубликаты

Иногда колонки называются так, что без слез не взглянешь: usr_nm_1, sal_rub_gross. Работать с этим неудобно. Переименовать колонки можно через словарь, где ключ — старое имя, а значение — новое.

# Метод rename принимает словарь с заменами
df = df.rename(columns={
    'Имя': 'name', 
    'Зарплата_руб': 'salary'
})
Pandas на Python: От чтения CSV до сложной аналитики за 1 статью - 21

И, наконец, классика жанра — кто-то случайно нажал кнопку “Отправить” дважды, и в базе появились одинаковые строки. Чтобы не задваивать статистику, сносим дубликаты одним мощным ударом:

# Оставляет только первое вхождение, остальные удаляет
df = df.drop_duplicates() 
Pandas на Python: От чтения CSV до сложной аналитики за 1 статью - 22

7. Группировка и агрегация (The Power of GroupBy)

Если бы мне сказали: «Оставь в Pandas только одну функцию, а остальные мы удалим», я бы, не задумываясь, выбрал .groupby(). Это альфа и омега любого анализа данных.

С помощью группировки сырые, бессмысленные строчки логов превращаются в бизнес-метрики. Ответить на вопросы вроде «Какой отдел тратит больше всего денег?», «В каком месяце у нас просели продажи?» или «Сколько в среднем живут пользователи из разных стран?» без нее просто невозможно.

Метод .groupby(): Принцип Split-Apply-Combine

Под капотом группировка работает по элегантному принципу «Раздели – Примени – Соедини».

  1. Split (Разделение): Pandas берет вашу огромную таблицу и разбивает ее на маленькие кучки по уникальным значениям в выбранной колонке. Например, кучка записей “Отдел Продаж”, кучка “IT”, кучка “HR”.

  2. Apply (Применение): К каждой из этих кучек применяется какая-то математическая функция (сумма, среднее, количество).

  3. Combine (Склейка): Результаты собираются обратно в новую, компактную табличку.

Звучит сложно, пишется в одну строку. Давайте посчитаем среднюю зарплату по ролям:

# 1. Группируем по колонке 'Роль'
# 2. Выбираем колонку, которую хотим посчитать ('Зарплата_руб')
# 3. Применяем функцию среднего (mean)
average_salary = df.groupby('Роль')['Зарплата_руб'].mean()

print(average_salary)
Pandas на Python: От чтения CSV до сложной аналитики за 1 статью - 23

Вывод будет выглядеть примерно так (это объект Series, где индексом стали названия ролей):

Роль
Data Analyst       180000.0
DevOps             220000.0
Product Manager    300000.0
Python Dev         250000.0
Pandas на Python: От чтения CSV до сложной аналитики за 1 статью - 24

А что, если мы хотим посчитать не только среднее, но и сумму, и количество сотрудников в каждом отделе? Писать три разных groupby? Ни в коем случае! Используем мощнейший метод .agg() (от слова aggregation):

# Передаем список нужных функций
stats = df.groupby('Роль')['Зарплата_руб'].agg(['mean', 'sum', 'count'])
Pandas на Python: От чтения CSV до сложной аналитики за 1 статью - 25

На выходе вы получите красивый датафрейм, где по строкам будут роли, а по колонкам — среднее, сумма и количество. Это уже готовый кусок отчета для руководства.

Сводные таблицы: pd.pivot_table() (Любимая игрушка аналитиков)

Если вы пришли из Excel, то при слове “Сводная таблица” (Pivot Table) у вас наверняка теплеет на душе. Это когда вы перетаскиваете поля в строчки и колонки, и магия случается сама собой.

В Pandas есть полный аналог этой функции — метод pivot_table. По сути, это тот же groupby, но с возможностью разложить данные не только по вертикали (строкам), но и по горизонтали (колонкам). Это нужно, когда вы хотите посмотреть на данные в разрезе двух и более параметров одновременно.

Допустим, у нас в таблице есть не только Роли, но и Города (Москва, Питер). Мы хотим посмотреть среднюю зарплату аналитиков в Москве и Питере в виде матрицы:

# Строим матрицу: Роль vs Город
pivot = pd.pivot_table(
    data=df,              # Наша таблица
    values='Зарплата_руб', # Что считаем
    index='Роль',         # Что пойдет в строки
    columns='Город',      # Что пойдет в столбцы
    aggfunc='mean',       # Как считаем (по умолчанию и так mean)
    fill_value=0          # Чем заполнить дыры, если аналитиков в Питере нет
)
Pandas на Python: От чтения CSV до сложной аналитики за 1 статью - 26

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

8. Объединение датафреймов (Франкенштейн из таблиц)

В реальной жизни данные редко лежат в одном удобном файле. Обычно у вас есть таблица с заказами (где указаны только ID товаров) и отдельная таблица со справочником товаров (где лежат их названия и цены). Или вам каждый месяц присылают новый файл с продажами, и к концу года у вас их ровно 12.

Чтобы собрать из этого зоопарка единую картину, в Pandas есть два главных инструмента склейки. Один работает “вниз” (по вертикали), другой — “вбок” (по горизонтали).

Вертикальное склеивание: pd.concat() (Пришить новые строки снизу)

Представьте, что у вас есть два датафрейма с абсолютно одинаковой структурой (одни и те же колонки). Например, df_jan (продажи за январь) и df_feb (продажи за февраль). Вам нужно просто дописать февральские строки в конец январских.

Для этого используется функция pd.concat() (от слова concatenation — сцепление). Она принимает список датафреймов, которые нужно склеить:

# У нас есть две таблички: df_jan и df_feb
# Склеиваем их в одну большую df_all
df_all = pd.concat([df_jan, df_feb])
Pandas на Python: От чтения CSV до сложной аналитики за 1 статью - 27

Важный нюанс: Помните, мы говорили про индексы (номера строк 0, 1, 2…)? При обычном concat() Pandas тупо приклеит вторую таблицу снизу вместе с её старыми индексами. В итоге у вас получится нумерация строк вида: 0, 1, 2, 0, 1, 2. Это чревато проблемами при поиске по индексу (loc).

Чтобы Pandas пересчитал индексы заново (0, 1, 2, 3, 4, 5), всегда добавляйте магический параметр ignore_index=True:

# Идеальное вертикальное склеивание
df_all = pd.concat([df_jan, df_feb], ignore_index=True)
Pandas на Python: От чтения CSV до сложной аналитики за 1 статью - 28

Горизонтальное слияние: pd.merge() (Знакомьтесь, это SQL JOIN в Python)

А теперь более сложный и частый кейс. У вас есть таблица df_orders (Заказы), где есть колонка client_id (например, число 105). И есть таблица df_clients (Клиенты), где напротив client_id = 105 написано имя “Иван Иванов” и его email.

Вам нужно подтянуть имя и email клиента в таблицу с заказами. В Excel для этого пишут километровую формулу ВПР (VLOOKUP). В базах данных используют JOIN. В Pandas есть гениальная функция pd.merge().

# Приклеиваем справочник клиентов (df_clients) к заказам (df_orders)
df_full = pd.merge(
    df_orders,       # Левая таблица (основная)
    df_clients,      # Правая таблица (справочник, откуда тянем данные)
    on='client_id',  # По какой общей колонке ищем совпадения (ключ)
    how='left'       # Как именно склеивать (тип джойна)
)
Pandas на Python: От чтения CSV до сложной аналитики за 1 статью - 29

Разбираемся с параметром how (Как склеивать?)

Параметр how определяет логику слияния, если в одной таблице есть ID, которого нет в другой. Это классическая теория множеств из SQL. Запомните 4 базовых сценария:

  1. how='left' (Left Join — самый частый!). Берем все строки из левой таблицы (Заказы) и ищем для них совпадения в правой (Клиенты). Если клиент с таким ID не найден в справочнике — заказ всё равно останется в итоговой таблице, просто вместо имени и email там будет пустота (NaN). Это самый безопасный способ обогатить данные, ничего не потеряв.

  2. how='inner' (Inner Join — пересечение). Оставляет только те строки, которые одновременно есть и в левой, и в правой таблице. Если клиент сделал заказ, но его почему-то нет в справочнике — этот заказ безжалостно удалится из итоговой таблицы. Используйте с осторожностью, чтобы не потерять данные!

  3. how='right' (Right Join). То же самое, что и Left, только наоборот. Берем всех клиентов из справочника и приклеиваем к ним их заказы. Если клиент ничего не заказывал — он всё равно будет в таблице, но с пустыми колонками заказа. Применяется редко (проще поменять таблицы местами и сделать left).

  4. how='outer' (Full Outer Join — объединение всего). Берет вообще всё из обеих таблиц. Останутся и заказы без клиентов, и клиенты без заказов (с кучей NaN везде, где нет совпадений).

Чаще всего (в 90% случаев) вы будете использовать именно how='left', чтобы просто подтянуть справочную информацию к основной таблице транзакций или логов.

9. Best Practices: Как писать код, за который не стыдно (и который не тормозит)

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

Вот три главных правила выживания.

Главный смертный грех: Никогда не используйте циклы for

Если вы пришли из обычного Питона, ваш мозг запрограммирован решать задачи перебором. Нужно изменить зарплату всем сотрудникам? Рука сама тянется написать что-то вроде:

# УЖАСНО: Никогда так не делайте в Pandas!
for index, row in df.iterrows():
    if row['role'] == 'Developer':
        df.loc[index, 'salary'] = row['salary'] * 1.2
Pandas на Python: От чтения CSV до сложной аналитики за 1 статью - 30

Знаете, что произойдет? На таблице в пару миллионов строк этот код будет работать минут пятнадцать. Pandas под капотом написан на C (через библиотеку NumPy), и когда вы используете питоновский цикл for, вы заставляете быстрый C-движок на каждой строчке спотыкаться и возвращать управление медленному Питону. Это как копать траншею чайной ложкой, имея за спиной экскаватор.

Решение — векторизация. Мы отдаем команду экскаватору сделать всё за один проход:

# ИДЕАЛЬНО: Отработает за миллисекунды
df.loc[df['role'] == 'Developer', 'salary'] *= 1.2
Pandas на Python: От чтения CSV до сложной аналитики за 1 статью - 31

Бейте себя по рукам каждый раз, когда хотите написать for для обхода датафрейма. В 99% случаев для вашей задачи уже есть встроенный векторизованный метод.

Метод .apply(): Спасательный круг для хитрой логики

Но что делать в том самом 1% случаев? Допустим, у вас есть колонка с текстом отзыва клиента, и вам нужно прогнать каждый отзыв через какую-то вашу самописную функцию (например, сложный парсер или API-запрос к нейросети), которую встроенными методами не опишешь.

Для этого существует метод .apply(). Он берет вашу функцию и аккуратно применяет ее к каждой ячейке колонки.

# Наша хитрая самописная функция
def extract_domain(email):
    if '@' in email:
        return email.split('@')[1]
    return 'unknown'

# Применяем функцию ко всей колонке
df['domain'] = df['email'].apply(extract_domain)

# Или то же самое через лямбда-функцию (для любителей однострочников)
df['domain'] = df['email'].apply(lambda x: x.split('@')[1] if '@' in x else 'unknown')
Pandas на Python: От чтения CSV до сложной аналитики за 1 статью - 32

Важная оговорка: .apply() — это, по сути, замаскированный цикл for. Он работает быстрее, чем ручной перебор, но всё равно медленнее чистой векторизации. Используйте его только тогда, когда встроенных инструментов Pandas действительно не хватает.

Chain formatting (Цепочки методов): Пишем как поэты

Как обычно выглядит код новичка, который чистит данные? Это бесконечное создание промежуточных переменных:

# Грязный код (плохо читается, жрет память)
df_clean = df.dropna()
df_filtered = df_clean[df_clean['age'] > 18]
df_grouped = df_filtered.groupby('city')['salary'].mean()
df_final = df_grouped.sort_values(ascending=False)
Pandas на Python: От чтения CSV до сложной аналитики за 1 статью - 33

В Pandas почти все методы возвращают новый датафрейм. А значит, мы можем прицеплять методы друг за другом, как вагоны поезда! Чтобы код не уехал за горизонт экрана, мы оборачиваем всё выражение в круглые скобки. Это позволяет Питону игнорировать переносы строк, и мы можем красиво писать каждый метод с новой строки:

# Чистый код (Method Chaining)
df_final = (
    df.dropna()
      .query('age > 18') # Альтернатива булевой фильтрации, очень удобна в цепочках
      .groupby('city')['salary']
      .mean()
      .sort_values(ascending=False)
)
Pandas на Python: От чтения CSV до сложной аналитики за 1 статью - 34

Посмотрите на этот блок! Он читается сверху вниз, как рецепт пирога: «Взять данные -> удалить пустые -> отфильтровать взрослых -> сгруппировать по городу -> найти среднюю зарплату -> отсортировать по убыванию». Никаких лишних переменных, никакого мусора в памяти, идеальная читаемость. Ваши коллеги скажут вам спасибо.

10. Заключение: Обратного пути нет

Давайте будем честны: как только вы уверенно освоите Pandas, открывать Excel для чего-то сложнее списка покупок вам больше не захочется. Да, поначалу синтаксис со всеми этими квадратными скобками, loc и лямбда-функциями может казаться перегруженным. Но кривая обучения окупается сполна.

Мы пробежались по самым верхам, но поверьте: то, что мы разобрали в этой статье (чтение I/O, фильтрация, очистка от пропусков, groupby и слияния) — это та самая база, которая закрывает 90% повседневных задач по работе с таблицами. Будь вы дата-сайентистом, бэкендером или маркетологом, которому скинули «эксельку на 5 гигов и попросили быстро свести стату» — этого арсенала вам хватит с головой.

Анонсы новых статей, полезные материалы, а так же если в процессе у вас возникнут сложности, обсудить их или задать вопрос по этой статье можно в моём Telegram-сообществе. Смело заходите, если что-то пойдет не так, — постараемся разобраться вместе.

Автор: enamored_poc

Источник

Rambler's Top100