Django-Admin.ru

Pandas для начинающих: DataFrame за 15 минут

Библиотека pandas в Python с нуля: установка, Series и DataFrame, чтение CSV и Excel, выборка loc/iloc, фильтрация, groupby, merge и сохранение результата.

Редакция Django-Admin.ru
· обновлено · 10 мин чтения

Содержание · 15 разделов
  1. Установка pandas
  2. Series и DataFrame: две главные структуры
  3. Чтение CSV и Excel
  4. Первый взгляд на данные: head, info, describe
  5. Выборка: столбцы, loc и iloc
  6. Фильтрация строк
  7. Сортировка
  8. Пропущенные значения
  9. Новые столбцы
  10. Группировка: groupby и агрегаты
  11. Объединение таблиц: merge и concat
  12. Сохранение результата: to_csv и to_excel
  13. Частые ошибки
  14. KeyError: ‘название столбца’
  15. Все данные в одном столбце
  16. UnicodeDecodeError при чтении CSV
  17. Изменение не сохранилось в DataFrame
  18. ModuleNotFoundError: No module named ‘pandas’
  19. Частые вопросы
  20. Как показать все столбцы и строки DataFrame?
  21. Что значит ParserError: Error tokenizing data?
  22. Как прочитать числа с запятой и пробелами вроде «1 200,50»?
  23. Как удалить дубликаты строк?
  24. Как загрузить в DataFrame данные из базы SQL?
  25. Нужен ли pyarrow для pandas 3.0?
  26. Итог

Pandas — библиотека Python для работы с таблицами: она читает CSV и Excel, фильтрует, группирует и считает данные, а затем сохраняет результат обратно в файл. Короткий ответ, с чего начать:

import pandas as pd

df = pd.read_csv("sales.csv")      # прочитать таблицу
print(df.head())                    # первые 5 строк
print(df.groupby("city")["price"].sum())  # сумма по городам

Ниже — всё, что нужно для первой реальной задачи с pandas в Python: от установки до отчёта в Excel. Примеры проверены на pandas 3.0 и Python 3.12; почти всё работает и в pandas 2.x — отличия отмечены отдельно.

Установка pandas

Pandas не входит в стандартную библиотеку, его ставят через pip. Лучше делать это в виртуальном окружении проекта:

# Windows
py -m pip install pandas openpyxl

# macOS / Linux
python3 -m pip install pandas openpyxl

openpyxl нужен для чтения и записи файлов .xlsx — без него read_excel() и to_excel() завершатся с ImportError. Подробнее об установке пакетов — в статьях про pip и установку библиотек Python.

Проверка:

import pandas as pd

print(pd.__version__)  # → 3.0.6 (у вас может быть другая версия)

Сокращение pd — общепринятое соглашение, его используют документация и почти все примеры в интернете.

Series и DataFrame: две главные структуры

Series — одномерный массив с подписями (индексом). Это один столбец таблицы:

s = pd.Series([10, 20, 30], index=["a", "b", "c"], name="score")
print(s["b"])     # → 20
print(s.mean())   # → 20.0

DataFrame — таблица из нескольких Series с общим индексом. Её удобно создать из словаря, где ключи — названия столбцов:

df = pd.DataFrame({
    "name": ["Анна", "Борис", "Вера"],
    "age": [28, 35, 22],
    "city": ["Москва", "Казань", "Москва"],
})
print(df)
#     name  age    city
# 0   Анна   28  Москва
# 1  Борис   35  Казань
# 2   Вера   22  Москва

print(df.shape)          # → (3, 3) — строки и столбцы
print(list(df.columns))  # → ['name', 'age', 'city']

Числа слева (0, 1, 2) — это индекс. По умолчанию он числовой, но индексом может быть и столбец с датами или идентификаторами.

Чтение CSV и Excel

Дальше все примеры используют файл sales.csv:

date,city,product,qty,price
2026-01-05,Москва,Ноутбук,2,85000
2026-01-05,Казань,Мышь,10,900
2026-01-06,Москва,Монитор,3,21000
2026-01-07,Пермь,Ноутбук,1,82000
2026-01-07,Казань,Монитор,,20500
2026-01-08,Москва,Мышь,15,850
df = pd.read_csv("sales.csv", parse_dates=["date"])

parse_dates сразу превращает столбец в даты. Полезные параметры read_csv():

ПараметрЗачем
sep=";"разделитель не запятая (типично для русского Excel)
encoding="cp1251"файл сохранён не в UTF-8
usecols=["city", "price"]прочитать только нужные столбцы
nrows=1000прочитать первые N строк — для проверки большого файла
index_col="date"сделать столбец индексом
dtype={"inn": str}задать тип столбца (например, не терять ведущие нули)

Excel-файлы читаются так же просто (нужен openpyxl):

df = pd.read_excel("report.xlsx", sheet_name="Продажи")
sheets = pd.read_excel("report.xlsx", sheet_name=None)  # словарь {имя листа: DataFrame}

Первый взгляд на данные: head, info, describe

df.head(3)   # первые 3 строки (по умолчанию 5)
df.tail(2)   # последние 2 строки
df.info()    # столбцы, типы, количество непустых значений
RangeIndex: 6 entries, 0 to 5
Data columns (total 5 columns):
 #   Column   Non-Null Count  Dtype
---  ------   --------------  -----
 0   date     6 non-null      datetime64[us]
 1   city     6 non-null      str
 2   product  6 non-null      str
 3   qty      5 non-null      float64
 4   price    6 non-null      int64

Уже здесь видно, что в qty одно пропущенное значение — поэтому столбец стал float64, а не целым. В pandas 2.x вывод отличается двумя типами: строковые столбцы там object, а даты — datetime64[ns]. В pandas 3.0 строки получают отдельный тип str, а даты из текста по умолчанию читаются с точностью до микросекунд (datetime64[us]).

describe() выводит статистику по числовым столбцам: количество, среднее, стандартное отклонение, минимум, квартили и максимум. Для текстовых столбцов полезен value_counts():

print(df["city"].value_counts())
# city
# Москва    3
# Казань    2
# Пермь     1

Выборка: столбцы, loc и iloc

df["city"]               # один столбец → Series
df[["city", "price"]]    # несколько столбцов → DataFrame (двойные скобки!)

Для строк есть два индексатора:

  • loc — по меткам: значениям индекса и названиям столбцов;
  • iloc — по позициям: номерам строк и столбцов, как в списке.
df.loc[0, "product"]          # → 'Ноутбук'
df.loc[0:2, ["city", "qty"]]  # строки с метками 0..2 включительно
df.iloc[0]                    # первая строка целиком
df.iloc[:2, :3]               # первые 2 строки и первые 3 столбца

Обратите внимание: срез в loc включает правую границу, а в iloc — нет, как в обычных списках Python.

Фильтрация строк

Условие над столбцом даёт Series из True/False, а её можно подставить в квадратные скобки:

df[df["price"] > 20000]

# Несколько условий: & (и), | (или), ~ (не); каждое условие — в скобках
df[(df["city"] == "Москва") & (df["price"] > 10000)]

# Значение из списка
df[df["city"].isin(["Казань", "Пермь"])]

# Поиск подстроки
df[df["product"].str.contains("Мон")]

# То же условие строкой
df.query("price > 20000 and city == 'Москва'")

Фильтр и выбор столбцов удобно совмещать в loc:

df.loc[df["city"] == "Москва", ["product", "qty"]]
#    product   qty
# 0  Ноутбук   2.0
# 2  Монитор   3.0
# 5     Мышь  15.0

Сортировка

df.sort_values("price", ascending=False).head(3)       # три самые дорогие позиции
df.sort_values(["city", "price"], ascending=[True, False])  # по городу, внутри — по цене
df.sort_index()                                         # по индексу

Методы pandas по умолчанию возвращают новый DataFrame и не меняют исходный. Результат нужно присвоить: df = df.sort_values("price").

Пропущенные значения

Пустые ячейки pandas хранит как NaN:

print(df.isna().sum())   # сколько пропусков в каждом столбце
# qty        1, остальные 0

df.dropna(subset=["qty"])                 # удалить строки, где qty пусто
df["qty"] = df["qty"].fillna(0).astype(int)  # заменить пропуски нулём и сделать целым

Вместо нуля пропуск можно заполнить средним: df["qty"].fillna(df["qty"].mean()). Что выбрать — зависит от смысла данных, универсального ответа нет.

Новые столбцы

Арифметика над столбцами выполняется сразу для всех строк — цикл не нужен:

df["total"] = df["qty"] * df["price"]
df["is_big"] = df["total"] > 100000
df["month"] = df["date"].dt.month       # часть даты через .dt
df["city_code"] = df["city"].map({"Москва": "MSK", "Казань": "KZN", "Пермь": "PRM"})

df = df.rename(columns={"qty": "quantity"})
df = df.drop(columns=["is_big"])

Для строк есть аксессор .str (df["city"].str.upper()), для дат — .dt. Метод apply() с функцией тоже работает, но он медленнее векторных операций — используйте его, когда без него не обойтись.

Группировка: groupby и агрегаты

groupby() разбивает таблицу на группы и считает по каждой итог — аналог GROUP BY в SQL и сводных таблиц Excel:

df.groupby("city")["total"].sum()
# city
# Казань      9000
# Москва    245750
# Пермь      82000

Несколько показателей сразу — через agg() с именованными агрегатами:

report = df.groupby("city").agg(
    orders=("product", "count"),
    revenue=("total", "sum"),
    avg_price=("price", "mean"),
)
#         orders  revenue     avg_price
# city
# Казань       2     9000  10700.000000
# Москва       3   245750  35616.666667
# Пермь        1    82000  82000.000000

Группировать можно по нескольким столбцам: df.groupby(["city", "product"])["quantity"].sum().reset_index(). reset_index() превращает группы обратно в обычные столбцы. Сводная таблица в стиле Excel строится через pivot_table():

df.pivot_table(index="city", columns="product", values="total", aggfunc="sum", fill_value=0)

Объединение таблиц: merge и concat

merge() соединяет две таблицы по ключу — как JOIN в SQL:

regions = pd.DataFrame({
    "city": ["Москва", "Казань", "Пермь"],
    "region": ["ЦФО", "ПФО", "ПФО"],
})
merged = df.merge(regions, on="city", how="left")

Параметр how задаёт тип соединения: "left", "right", "inner" (по умолчанию) или "outer". Если ключи называются по-разному, используйте left_on= и right_on=.

pd.concat([df1, df2]) просто склеивает таблицы с одинаковыми столбцами одну под другой — например, выгрузки за разные месяцы.

Сохранение результата: to_csv и to_excel

df.to_csv("result.csv", index=False, encoding="utf-8-sig")
df.to_excel("result.xlsx", index=False, sheet_name="Продажи")
  • index=False — не записывать числовой индекс отдельным столбцом;
  • encoding="utf-8-sig" — чтобы Excel на Windows корректно показал кириллицу в CSV.

Несколько листов в одном файле:

with pd.ExcelWriter("report.xlsx") as writer:
    df.to_excel(writer, sheet_name="Данные", index=False)
    report.to_excel(writer, sheet_name="Итоги")

Частые ошибки

KeyError: ‘название столбца’

Столбца с таким именем нет. Проверьте df.columns: часто в названии лишний пробел или другой регистр. Пробелы убирает df.columns = df.columns.str.strip().

Все данные в одном столбце

CSV сохранён с разделителем ;, а pandas по умолчанию ждёт запятую. Укажите sep=";".

UnicodeDecodeError при чтении CSV

Файл не в UTF-8 — обычно это выгрузка из старых программ под Windows. Попробуйте encoding="cp1251".

Изменение не сохранилось в DataFrame

Цепочка вида df["price"][0] = 1 (chained assignment) в pandas 3.0 никогда не меняет исходную таблицу: промежуточный результат ведёт себя как копия, а pandas выдаёт предупреждение ChainedAssignmentError. В pandas 2.x итог зависел от операции, и о риске предупреждал SettingWithCopyWarning. Присваивайте за один шаг через loc:

df.loc[df["city"] == "Москва", "price"] = 0

Та же причина у «пропавших» результатов sort_values(), dropna(), rename(): они возвращают новый объект, который нужно присвоить.

ModuleNotFoundError: No module named ‘pandas’

Pandas установлен в другой интерпретатор или окружение. Ставьте его командой python -m pip install pandas тем же Python, которым запускаете скрипт. Подробный разбор — в статье про ModuleNotFoundError.

Частые вопросы

Как показать все столбцы и строки DataFrame?

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

pd.set_option("display.max_columns", None)  # все столбцы
pd.set_option("display.max_rows", 200)      # до 200 строк вместо 60 по умолчанию
pd.set_option("display.width", None)        # ширина по размеру терминала

Снимать лимит строк полностью (None) на таблицах в сотни тысяч строк не стоит — вывод займёт весь терминал. Для просмотра выборочно используйте head(), tail() и sample().

Что значит ParserError: Error tokenizing data?

pandas.errors.ParserError: Error tokenizing data. C error: Expected 2 fields in line 3, saw 4

В строке 3 файла больше разделителей, чем в заголовке. Обычно неверно указан sep (например, ; внутри данных при запятой по умолчанию) или в тексте есть неэкранированные кавычки. Проверьте разделитель, а битые строки при необходимости пропустите параметром on_bad_lines="skip".

Как прочитать числа с запятой и пробелами вроде «1 200,50»?

Укажите десятичный разделитель и разделитель тысяч — тогда столбец сразу станет числовым:

df = pd.read_csv("ru.csv", sep=";", decimal=",", thousands=" ")
print(df["Сумма"].sum())  # → 2180.5

Если в выгрузке из Excel вместо обычного пробела неразрывный, передайте thousands="\xa0".

Как удалить дубликаты строк?

drop_duplicates() оставляет первую из одинаковых строк. Параметр subset сравнивает только выбранные столбцы, keep="last" оставляет последнее вхождение:

df = df.drop_duplicates()
df = df.drop_duplicates(subset=["city"], keep="last")  # одна строка на город

Как загрузить в DataFrame данные из базы SQL?

pd.read_sql() принимает SQL-запрос и подключение. Для SQLite хватит модуля sqlite3, для PostgreSQL и MySQL обычно передают движок SQLAlchemy:

import sqlite3

conn = sqlite3.connect("library.db")
books = pd.read_sql("SELECT title, year FROM books WHERE year < ?", conn, params=(1850,))

Обратная операция — df.to_sql("books", conn, if_exists="append", index=False). Подробнее о работе с базами — в статье про SQLAlchemy.

Нужен ли pyarrow для pandas 3.0?

Нет, pyarrow — необязательная зависимость. Если он установлен, строковый тип str хранит данные в формате Apache Arrow, это экономит память и ускоряет операции со строками; без него pandas использует обычное хранение. Для форматов Parquet и Feather pyarrow нужен: pip install pyarrow.

Итог

Для большинства задач хватает десятка приёмов: read_csv/read_excel, head и info, фильтрация через loc, groupby().agg(), merge и to_excel. Полный справочник — в официальной документации pandas. Другие инструменты для данных, сети и графики собраны в обзоре библиотек Python, а загрузить данные из веб-API поможет библиотека requests.

  • #Python
  • #pandas
  • #DataFrame
  • #Анализ данных
  • #Excel
  • #CSV
↑ ↓ выборEnter открытьEsc закрыть