pandas превращает CSV в таблицу DataFrame, где фильтр, группировка и график занимают несколько проверяемых операций. Возьмём небольшой файл продаж, очистим цену и количество, оставим оплаченные строки, посчитаем выручку по категориям и сохраним bar chart. Параллельно научимся не доверять dtype и пропускам.
CSV выглядит как таблица, но цена может оказаться строкой, пустая категория превращается в NaN, а разделитель зависит от источника. Анализ начинается с проверки структуры. В этой статье вы соберёте мини-отчёт sales_report.csv и график revenue.png. Финальный результат можно проверить без догадок: терминал печатает три категории по убыванию выручки, а PNG совпадает с сохранённой агрегированной таблицей.
read_csv загружает строки и позволяет сразу проверить shape и dtypes.
Новый столбец revenue умножает price на quantity только после очистки.
groupby и plot превращают строки в топ и понятный PNG.
Что проверить сразу после read_csv
Файл sales.csv является входом, DataFrame хранит строки в памяти, а report содержит одну строку на category. Скрипт не перезаписывает исходник. Числовые преобразования выполняются явно до формулы revenue. Для pandas держите этапы раздельно: ввод, проверка, основное действие и вывод. Такой маршрут позволяет остановиться в конкретной точке, увидеть фактические данные и исправить одну причину вместо случайной перестановки строк.
| Этап | Действие | Проверяемый результат |
|---|---|---|
| Загрузка | read_csv читает заголовки и строки | shape показывает размер |
| Очистка | to_numeric отмечает неверные числа | Проблемы становятся NaN |
| Агрегация | groupby суммирует revenue | Одна строка на категорию |
| Экспорт | to_csv и savefig пишут артефакты | Есть таблица и PNG |
Каждый промежуточный DataFrame можно вывести и сверить до следующего преобразования. У pandas каждый этап оставляет наблюдаемый след, поэтому следующий шаг начинается только после проверки предыдущего.

От входных данных до видимого результата. График строится только из проверенной таблицы
Пишем анализ продаж по шагам
Создайте проект uv init sales-report и установите uv add pandas matplotlib. Сохраните sales.csv в той же папке, затем запустите uv run python report.py. Matplotlib нужен только для PNG. На сервере без окна скрипт всё равно работает, потому что использует savefig, а не интерактивный show.
from pathlib import Path
import matplotlib.pyplot as plt
import pandas as pd
source = Path("sales.csv")
data = pd.read_csv(source)
required = {"category", "price", "quantity", "status"}
missing = required - set(data.columns)
if missing:
raise ValueError(f"missing columns: {sorted(missing)}")
data["price"] = pd.to_numeric(data["price"], errors="coerce")
data["quantity"] = pd.to_numeric(data["quantity"], errors="coerce")
invalid = data[data[["price", "quantity"]].isna().any(axis=1)]
if not invalid.empty:
raise ValueError(f"invalid numeric rows: {invalid.index.tolist()}")
paid = data.loc[data["status"].eq("paid")].copy()
paid["revenue"] = paid["price"] * paid["quantity"]
report = (
paid.groupby("category", as_index=False)["revenue"]
.sum()
.sort_values("revenue", ascending=False)
)
print(report.to_string(index=False))
report.to_csv("sales_report.csv", index=False)
ax = report.plot.bar(x="category", y="revenue", legend=False)
ax.set_ylabel("Revenue")
ax.figure.tight_layout()
ax.figure.savefig("revenue.png", dpi=160)
plt.close(ax.figure)- Набор обязательных колонок проверяется до формул.
- Неверное число выдаёт индекс проблемной строки.
- В отчёт попадают только строки status=paid.
- sales_report.csv и revenue.png строятся из одной таблицы report.
Использование .copy() после фильтра делает намерение явным и защищает от неоднозначного изменения представления исходного DataFrame. Пример pandas специально ограничен одним пользовательским сценарием, чтобы назначение каждой строки оставалось видимым.

Что отличает устойчивый проект от случайного запуска. Ошибки данных остаются видимыми
Как работают фильтр, groupby и sum
DataFrame хранит каждый столбец с dtype. pd.to_numeric с errors="coerce" превращает неверное значение в NaN, после чего скрипт сам выбирает строгий отказ. loc принимает булеву маску той же длины. groupby собирает строки с одинаковой category, sum уменьшает каждую группу до одного числа, sort_values задаёт порядок топа. plot.bar возвращает Matplotlib Axes, поэтому подпись оси и сохранение настраиваются после построения. Индекс не нужен в итоговом CSV, поэтому index=False.
| Часть | За что отвечает | Что проверить |
|---|---|---|
| read_csv | Загружает таблицу | Разделитель и кодировка верны |
| dtypes | Показывает тип столбца | price и quantity числовые |
| loc | Фильтрует оплаченные строки | Маска имеет dtype bool |
| groupby | Собирает категории | Пропуски обработаны явно |
| savefig | Записывает график | PNG существует и не пустой |
По умолчанию groupby может исключить NaN-ключи, поэтому пустую category надо либо отклонить, либо заполнить до группировки. Большой CSV читайте частями через chunksize, если он не помещается в память. Даты лучше разбирать через parse_dates или pd.to_datetime. Денежные расчёты на float подходят для учебного графика, но бухгалтерский результат требует Decimal или хранения копеек целым числом. Не округляйте каждую строку без требования: сумма округлённых значений может отличаться от округлённой суммы.
Ломаем CSV и проверяем устойчивость отчёта
Запустите исходный файл. Затем замените одну цену на word и получите индекс ошибки. Верните число, добавьте пустую category и выберите политику: отклонить строку или заполнить "Unknown". Добавьте колонку date, разберите её и постройте выручку по дням. Проверьте дубликат строки через duplicated. Последний шаг: добавьте аргумент командной строки для пути CSV, чтобы скрипт не зависел от имени sales.csv.
- Проверьте shape и список columns.
- Сломайте числовое значение.
- Отфильтруйте только paid.
- Сверьте сумму revenue вручную.
- Добавьте обработку пустой category.
- Сохраните отчёт и график повторно.
- Типы проверены до формулы.
- Неверная строка названа.
- Топ отсортирован убывающе.
- CSV и PNG согласованы.
Отчёт воспроизводим, когда один и тот же вход даёт те же строки, порядок и файл изображения. После этой проверки измените одно правило pandas и заранее запишите ожидаемый результат. Так копирование превращается в понимание.

Четыре проверки перед следующим шагом. Один report питает оба артефакта
Как развивать анализ без магических строк
Следующим шагом вынесите загрузку, очистку и агрегацию в отдельные функции и напишите тесты на маленьком DataFrame. Для исследовательской работы сохраните notebook, но итоговую логику держите в скрипте, который можно перезапустить. Добавьте описание единиц и периода рядом с графиком. Не удаляйте строки молча через dropna без отчёта о количестве. Для большого проекта храните сырой файл отдельно от очищенного и фиксируйте версию источника.
Как изучить тему в Кодике
Начните со списков и словарей Python, затем сравните их с колонками и строками DataFrame. В Кодике сначала восстановите чистую логику без фреймворка, затем верните библиотеку и интерфейс pandas.
| Шаг | Что разобрать | Мини-проверка |
|---|---|---|
| 1 | Файлы и Path | Проверить существование CSV |
| 2 | Типы и ошибки | Отклонить неверную цену |
| 3 | Условия и маски | Оставить paid |
| 4 | Группировка | Посчитать сумму category |
| 5 | Визуализация | Сохранить bar chart |
Сначала получите правильную таблицу report, только затем добавляйте подписи и цвета графика. Финальная проверка для pandas: закрыть статью, объяснить путь данных и добавить одну функцию без копирования готового блока.
Преобразуйте числа явно и обработайте NaN.
Покажите индексы или количество исключённых строк.
Используйте .copy() перед созданием нового столбца.
Сохраните тот же порядок в report и CSV.
Что получится в итоге

Исходный CSV превращается в проверенный топ категорий, а таблица и график сохраняются как два согласованных результата.
Зачем после read_csv смотреть dtypes?
dtypes показывает, распознал ли pandas цену и количество как числа, а не строки object.
Что делает groupby в pandas?
groupby собирает строки по ключу, после чего агрегатор вроде sum считает результат для каждой группы.
Почему после loc используется copy?
copy создаёт самостоятельный DataFrame перед добавлением revenue и убирает неоднозначное изменение view.
Как понять, что учебный проект pandas действительно работает?
Проверьте основной сценарий pandas, неверный ввод, повторный запуск и один граничный случай. Затем объясните путь данных своими словами.
Можно ли начать с готового кода pandas из статьи?
Да. Сначала добейтесь результата pandas, затем измените одно правило и восстановите ключевой файл без копирования.
Python, списки и файлы закрепите в курсе Python. Проверки логики добавьте по материалу про pytest.
Для небольших утилит сравните генерацию QR-кода и генератор случайных чисел, где также важны входные данные и проверяемый файл.