pandas: устройство, выборка и изменение таблиц

Series и DataFrame: создание, index, columns, shape, dtypes

Содержание курса

Метка (label) и позиция (position): в чём разница

У каждой строки в Series или DataFrame есть два способа её идентифицировать: по метке и по позиции. Это разные вещи, хотя при стандартном целочисленном индексе они выглядят одинаково.

Позиция — это порядковый номер элемента, считая от нуля. Первый элемент всегда на позиции 0, второй — на позиции 1, и так далее. Позиция не хранится явно нигде: она просто следует из порядка.

Метка — это значение из index, которое pandas хранит и использует для обращения к строке по имени. Метка может быть целым числом, строкой, датой — чем угодно.

Когда создаёшь Series из списка, pandas автоматически ставит метки 0, 1, 2, … Это RangeIndex, и в нём метка и позиция совпадают численно:

import pandas as pd

s = pd.Series([100, 200, 300])
print(list(s.index))  # [0, 1, 2]

Элемент на позиции 0 имеет метку 0, на позиции 1 — метку 1. Выглядит одинаково, но это совпадение, а не тождество.

Как только создаёшь Series из словаря с нецелочисленными ключами, совпадение пропадает:

s2 = pd.Series({'x': 10, 'y': 20, 'z': 30})
print(list(s2.index))  # ['x', 'y', 'z']

Здесь метки — это 'x', 'y', 'z'. Позиции по-прежнему 0, 1, 2. Метка 'y' находится на позиции 1 — это разные идентификаторы одного и того же элемента.

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

Особенно наглядно разрыв между меткой и позицией виден, когда DataFrame создаётся с нестандартным индексом. Представь, что данные уже пришли в таком порядке — строки с метками 2, 0, 1:

df = pd.DataFrame(
    {
        'name':  ['Вера', 'Анна', 'Борис'],
        'score': [78, 85, 92]
    },
    index=[2, 0, 1]  # метки строк заданы явно
)
print(df)
#     name  score
# 2   Вера     78
# 0   Анна     85
# 1  Борис     92

print(df.index.tolist())  # [2, 0, 1]

Строка с меткой 2 (Вера) находится на позиции 0 — первая физически. Строка с меткой 0 (Анна) — на позиции 1. Метки здесь не совпадают с позициями: метка 0 не означает «первая строка».

Если обращаться к этому DataFrame по позиции, на нулевой позиции окажется Вера. Если по метке 0 — Анна. Это ровно та точка, где путаница между меткой и позицией начинает давать неверные результаты — и именно поэтому pandas предоставляет разные инструменты для каждого из этих двух способов обращения к данным.