Нашли ошибку?
среднийpandas 3.0.6

Выравнивание по индексу

Почему арифметика двух Series сопоставляет значения по меткам и откуда в результате появляются NaN.

Нужно знать:SeriesDataFrame

Содержание статьи

Коротко

  • Операции между Series и таблицами выполняются по совпадающим меткам индекса, а не по позициям. Порядок строк не важен.
  • Метка есть только в одном из объектов — в результате NaN, а набор меток — объединение обоих.
  • Методы add, sub, mul, div с fill_value=0 считают отсутствующее значение нулём.
  • reindex(метки) приводит объект к нужному набору меток; align выравнивает два объекта друг по другу.
  • Присваивание Series в столбец (df["new"] = s) тоже идёт по меткам. Массив NumPy или список — по позициям.

Синтаксис

s1 + s2                         # выравнивание по меткам
s1.add(s2, fill_value=0)        # так же sub, mul, div
s.reindex(new_labels, fill_value=None)
a, b = s1.align(s2, join="outer")

Параметры

ПараметрЧто делаетПо умолчанию
fill_valueзначение для отсутствующей метки перед операцией / при reindexNone
joinв align: "outer", "inner", "left", "right""outer"

Примеры

Данные для примеровиспользуются во всех примерах ниже
plan = pd.Series({"Омск": 100, "Тула": 80, "Сочи": 60})
fact = pd.Series({"Тула": 90, "Омск": 110, "Пермь": 40})
Арифметика по меткам
fact - plan                          # по меткам, а не по позициям; порядок не важен
Вывод
Омск     10.0
Пермь     NaN
Сочи      NaN
Тула     10.0
dtype: float64
Отсутствующее значение — ноль
fact.sub(plan, fill_value=0)         # отсутствующая метка считается нулём
Вывод
Омск     10.0
Пермь    40.0
Сочи    -60.0
Тула     10.0
dtype: float64
reindex — нужный набор меток
plan.reindex(["Омск", "Тула", "Пермь"])            # новый набор меток; новых нет — NaN
Вывод
Омск     100.0
Тула      80.0
Пермь      NaN
dtype: float64
reindex с заполнением
plan.reindex(["Омск", "Тула", "Пермь"], fill_value=0)
Вывод
Омск     100
Тула      80
Пермь      0
dtype: int64
align — общие метки
a, b = plan.align(fact, join="inner")              # только общие метки
a, b
Вывод
(Омск    100
Тула     80
dtype: int64, Омск    110
Тула     90
dtype: int64)
Новый столбец выравнивается
df = pd.DataFrame({"plan": plan})
df["fact"] = fact                                   # новый столбец тоже выравнивается по индексу
df
Вывод
      plan   fact
Омск   100  110.0
Тула    80   90.0
Сочи    60    NaN

Подводные камни

Метки не совпали — одни NaN

Если индексы двух объектов не пересекаются (например, после reset_index у одного из них), результат будет из одних NaN. Проверьте индексы или переходите к позиционной работе через to_numpy().

Массив вместо Series

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

Столбец из массива
df = pd.DataFrame({"plan": plan})
df["fact"] = fact.to_numpy()[:3]                    # массив без индекса — по порядку позиций
df
Вывод
      plan  fact
Омск   100    90
Тула    80   110
Сочи    60    40