Нашли ошибку?
Скачать чистый
урок 1 из 3≈ 20 минупражнения: 0 из 3

Индекс

Сделать столбец индексом — set_index — и находить строки по осмысленным меткам; вернуть индекс в столбцы — reset_index; index_col при чтении файла; срезы по отсортированному индексу; что бывает, когда метки повторяются.

Python запустится при первом выполнении

С индексом мы встречаемся с первого урока, но до сих пор он был в основном номерами строк. Иногда метки оказывались осмысленными — города после группировки, названия показателей в describe, — и тогда по ним было удобно искать. Пора взять это в свои руки: назначать индекс самим.

Индекс как ключ

В справочнике товаров у каждой строки есть естественный «адрес» — код товара. Но сейчас он лежит в обычном столбце, а в индексе — номера:

[ ]Индекс по умолчанию
import pandas as pd

products = pd.read_csv("data/products.csv")
products.head(3)
Выводсохранённый · нажмите «Выполнить», чтобы получить свой
product_id name category price cost
0 P01 Эспрессо-смесь 1 кг Кофе 1450 870
1 P02 Колумбия 250 г Кофе 690 380
2 P03 Эфиопия 250 г Кофе 790 430

Чтобы найти товар по коду, нужен фильтр:

[ ]Поиск фильтром
products[products["product_id"] == "P05"]
Выводсохранённый · нажмите «Выполнить», чтобы получить свой
product_id name category price cost
4 P05 Кофе без кофеина 250 г Кофе 720 410

Метод set_index делает столбец индексом:

[ ]Код товара — в индексе
catalog = products.set_index("product_id")
catalog.head(3)
Выводсохранённый · нажмите «Выполнить», чтобы получить свой
name category price cost
product_id
P01 Эспрессо-смесь 1 кг Кофе 1450 870
P02 Колумбия 250 г Кофе 690 380
P03 Эфиопия 250 г Кофе 790 430

Столбец product_id переехал влево: теперь это подписи строк, а его название стоит над индексом. Искать по метке можно напрямую — через loc:

[ ]Строка и ячейка по коду
print(catalog.loc["P05", "price"])
catalog.loc["P05"]
Выводсохранённый · нажмите «Выполнить», чтобы получить свой
720
name        Кофе без кофеина 250 г
category                      Кофе
price                          720
cost                           410
Name: P05, dtype: object

catalog.loc["P05", "price"] читается как адрес в электронной таблице: строка P05, столбец price.

Вопрос

В таблице products пять столбцов. На сколько столбцов меньше в catalog = products.set_index("product_id")?

Из этого следует ловушка: как к столбцу к индексу обратиться уже нельзя.

[ ]Столбца product_id больше нетошибка: KeyError
catalog["product_id"]
Ошибкасохранённый · нажмите «Выполнить», чтобы получить свой
KeyError: 'product_id'
[ ]Название индекса, метки и проверка «есть ли такая»
print(catalog.index.name)
print(list(catalog.index[:4]))
print("P05" in catalog.index, "P99" in catalog.index)
Выводсохранённый · нажмите «Выполнить», чтобы получить свой
product_id
['P01', 'P02', 'P03', 'P04']
True False

Как и остальные методы, set_index возвращает новую таблицу — products не изменилась.

[ ]Упражнение 1Поиск по коду клиента решено

То же — со справочником клиентов. Сохраните в clients таблицу customers с customer_id в индексе. Достаньте город клиента C012 и сохраните в c012_city. В picked сохраните строки клиентов C005, C100, C200 — только столбцы name и segment.

customers = pd.read_csv("data/customers.csv")
clients = ...
c012_city = ...
picked = ...

Метки, которой нет, loc не находит:

[ ]Товара P99 нетошибка: KeyError
catalog.loc["P99"]
Ошибкасохранённый · нажмите «Выполнить», чтобы получить свой
KeyError: 'P99'

Туда и обратно

Вернуть индекс в обычные столбцы умеет знакомый reset_index:

[ ]Индекс снова в столбце
catalog.reset_index().head(2)
Выводсохранённый · нажмите «Выполнить», чтобы получить свой
product_id name category price cost
0 P01 Эспрессо-смесь 1 кг Кофе 1450 870
1 P02 Колумбия 250 г Кофе 690 380

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

А назначить индекс можно сразу при чтении файла — параметром index_col:

[ ]Индекс при загрузке
pd.read_csv("data/products.csv", index_col="product_id").head(2)
Выводсохранённый · нажмите «Выполнить», чтобы получить свой
name category price cost
product_id
P01 Эспрессо-смесь 1 кг Кофе 1450 870
P02 Колумбия 250 г Кофе 690 380

Срез по меткам

Индексом может быть любой столбец. Возьмём название товара:

[ ]Цена по названию
named = products.set_index("name")
named.loc["Зефир", "price"]
Выводсохранённый · нажмите «Выполнить», чтобы получить свой
np.int64(210)

Срезы по меткам вы знаете с урока о loc. Если индекс отсортирован, границами среза могут быть и значения, которых в индексе нет, — например, отдельные буквы. Срез от "Т" до "Ф" вернёт все названия, которые по алфавиту лежат между этими буквами:

[ ]Товары от Т до Ф
named = named.sort_index()
named.loc["Т":"Ф", "price"]
Выводсохранённый · нажмите «Выполнить», чтобы получить свой
name
Термокружка           1150
Травяной сбор 50 г     260
Турка медная          2400
Улун 100 г             540
Name: price, dtype: int64

«Френч-пресс» и «Фильтры» не попали: по алфавиту они идут после строки "Ф" — как в словаре слово «фильтр» стоит после буквы «ф». Поэтому, чтобы захватить все названия на «Ф», правой границей берут следующую букву — "Х".

На неотсортированном индексе такой срез вызовет ошибку — pandas не сможет определить, где начинается и где кончается диапазон. Сначала sort_index().

[ ]Упражнение 2Товары на букву К решено

Сохраните в by_name таблицу products с названием товара в индексе, отсортированную по индексу. В k_products сохраните товары, названия которых начинаются на «К», — срезом меток. В k_mean сохраните их среднюю цену.

by_name = ...
k_products = ...
k_mean = ...

Когда метки повторяются

Метки индекса не обязаны быть уникальными. Сделаем индексом номер заказа — а в заказе бывает несколько строк:

[ ]Индекс с повторами
orders = pd.read_csv("data/shop_orders.csv").set_index("order_id")
print(orders.index.is_unique)
orders.loc[10001]
Выводсохранённый · нажмите «Выполнить», чтобы получить свой
False
date customer_id city channel category product price quantity
order_id
10001 2025-01-01 C095 Москва маркетплейс Аксессуары Кофемолка ручная 3200 2
10001 2025-01-01 C095 Москва маркетплейс Чай Травяной сбор 50 г 260 1

loc[10001] вернул таблицу из двух строк — всех с этой меткой. Удобно: «покажи заказ 10001» — одна короткая запись. Но есть подвох: результат меняет тип в зависимости от данных.

[ ]Две строки — таблица, одна строка — Series
print(type(orders.loc[10001]))
print(type(orders.loc[11576]))
Выводсохранённый · нажмите «Выполнить», чтобы получить свой
<class 'pandas.DataFrame'>
<class 'pandas.Series'>

Если метка встречается один раз, loc возвращает строку как Series, если несколько — таблицу. Код, написанный в расчёте на одно, сломается на другом. Поэтому индекс с повторами хорош для просмотра, а для расчётов надёжнее уникальный ключ — или обычные столбцы и groupby.

[ ]Упражнение 3Один заказ решено

Сохраните в order_10140 строки заказа с номером 10140, в n_lines — их число, в order_sum — сумму заказа (цена × количество по всем его строкам). Затем верните номер заказа в столбцы: сохраните в flat таблицу orders с обычным индексом.

order_10140 = ...
n_lines = ...
order_sum = ...
flat = ...

Итоги

  • set_index("столбец") делает столбец индексом; reset_index() возвращает его в столбцы.
  • таблица.loc[метка] — строка по метке; таблица.loc[метка, "столбец"] — ячейка.
  • index_col="столбец" в read_csv назначает индекс при загрузке.
  • Срез по значениям, которых нет среди меток (буквы, неполные названия), работает только на отсортированном индексе; конец среза входит.
  • Индекс может содержать повторы — тогда loc возвращает несколько строк.

Подробнее в справочнике

Нашли ошибку?