Какие ключевые абстракции Pandas нужно понимать, чтобы не получать формально рабочие, но неверные результаты?
Ключевые абстракции Pandas: выравнивание по Index (не по позиции), семантика view/copy с SettingWithCopyWarning, неявная конвертация dtype, порядок строк в GroupBy и тихое дублирование при merge без validate.
Ключевые абстракции Pandas
Pandas строится на нескольких концептах, непонимание которых порождает формально работающий, но семантически неверный код.
1. Index и выравнивание по оси
В отличие от NumPy, операции между двумя Series/DataFrame выравниваются по Index, а не по позиции. Это часто приводит к неожиданным NaN.
import pandas as pd
a = pd.Series([1, 2, 3], index=[0, 1, 2])
b = pd.Series([10, 20, 30], index=[1, 2, 3]) # сдвинутый индекс
print(a + b)
# 0 NaN ← index=0 есть только в a
# 1 12.0
# 2 22.0
# 3 NaN ← index=3 есть только в b
Решение: a.values + b.values (NumPy-массивы без индекса) или явный reset_index.
2. View vs Copy — SettingWithCopyWarning
Pandas не гарантирует, возвращает ли операция view (вид на исходные данные) или copy (новый объект). Мутация view меняет оригинал; мутация copy — нет.
df = pd.DataFrame({"a": [1, 2, 3], "b": [4, 5, 6]})
# НЕВЕРНО — может не изменить df, SettingWithCopyWarning
subset = df[df["a"] > 1]
subset["b"] = 99 # может быть copy, df не изменится
# ВЕРНО — явная копия или .loc
subset = df[df["a"] > 1].copy()
subset["b"] = 99 # безопасно
# или через .loc на оригинальном df
df.loc[df["a"] > 1, "b"] = 99
В Pandas 2.x включён Copy-on-Write (CoW) по умолчанию — поведение стало предсказуемее, но старый код может сломаться.
3. dtype и скрытые преобразования
При чтении CSV Pandas выводит dtype эвристически. NaN в целочисленной колонке конвертирует её в float64, что ломает join-ы по ключу.
df = pd.read_csv("orders.csv", dtype={"user_id": "Int64"}) # nullable integer
print(df.dtypes)
# user_id Int64 ← сохраняет NaN без float-конвертации
4. GroupBy — split-apply-combine и порядок строк
После groupby/apply порядок строк может измениться. Если следующий шаг зависит от порядка (например, lag/shift по времени), результат будет неверным без явной сортировки.
df = pd.DataFrame({
"user": [1, 1, 2, 2],
"date": pd.to_datetime(["2025-01-02", "2025-01-01", "2025-01-03", "2025-01-01"]),
"amount": [100, 200, 50, 150],
})
# НЕВЕРНО — shift без сортировки даёт lag на неверных строках
df["prev"] = df.groupby("user")["amount"].shift(1)
# ВЕРНО — сначала сортировка внутри группы
df = df.sort_values(["user", "date"])
df["prev"] = df.groupby("user")["amount"].shift(1)
5. merge — тип join-а и дублирование строк
По умолчанию pd.merge() делает inner join и не предупреждает, если один ключ встречается несколько раз — строки молча дублируются (cartesian product).
# Явная валидация: ключ уникален в правой таблице
result = pd.merge(
orders, users,
on="user_id",
how="left",
validate="many_to_one", # выбросит MergeError при дублях
)
Подводные камни
- Выравнивание по Index — операции между DataFrame с разными индексами порождают NaN без предупреждений
- SettingWithCopyWarning — игнорирование этого предупреждения приводит к скрытым мутациям или их отсутствию
- Смешение
.loc(label-based) и.iloc(position-based) при нецелочисленном индексе даёт разные строки - apply() с lambda возвращает Series или DataFrame в зависимости от формы — shape выхода непредсказуем без явного
result_type - inplace=True не гарантирует отсутствие копии и не даёт выигрыша по памяти в большинстве случаев
- read_csv без explicit dtype — тихая конвертация типов, особенно опасна для ID-колонок с ведущими нулями (телефоны, коды)
- pivot_table молча агрегирует дубли через aggfunc=mean, если не указано иное — данные теряются без ошибки
What hurts your answer
- Знать термины Pandas, но не понимать связи между абстракциями
- Объяснять поведение через отдельные примеры вместо причинной модели
- Не связывать mental model с диагностикой ошибок
What they're listening for
- Понимает ключевые абстракции Pandas
- Может предсказывать поведение системы через mental model
- Связывает модель с debugging и production decisions