df = DataFrame.reindex(labels=None, *, index=None, columns=None, axis=None, method=None, copy=None, level=None, fill_value=nan, limit=None, tolerance=None) s = Series.reindex(index=None, *, method=None, copy=None, level=None, fill_value=None, limit=None, tolerance=None)
labels=None
- новые метки/индекс для соответствия оси, заданной axis
.
index=None
- новые метки для индекса. Предпочтительно объект Index
, чтобы избежать дублирования данных.
columns=None
- новые метки для столбцов. Предпочтительно объект Index
, чтобы избежать дублирования данных. Объект Series
этот аргумент не использует.
axis=None
- может быть либо именем оси 'index'
/'columns'
, либо числом 0/1. Объект Series
этот аргумент не использует.
method=None
- метод, используемый для заполнения NA
в переиндексированном DataFrame
/Series
. Обратите внимание: метод применим только к монотонно растущим/уменьшающимся индексам.
None
(по умолчанию): не заполнять пробелыpad
/ffill
: использовать последнее достоверное наблюдение для заполнения NA
backfill
/bfill
: использовать следующее достоверное наблюдение для заполнения NA
.nearest
: использовать ближайшие достоверные наблюдения для заполнения NA
.copy=None
- возвращает новый объект, даже если переданные индексы совпадают.
Аргумент
copy
изменит поведение в pandas 3.0. Копирование при записи будет включено по умолчанию, а это означает, что все методы с аргументомcopy
будут использовать механизм отложенного копирования и игнорировать аргументcopy
. Ключевой аргументcopy
будет удален в будущей версииpandas
. Можно уже сейчас получить будущее поведение и улучшения, включив копирование при записиpd.options.mode.copy_on_write = True
level=None
- сопоставляет значения индекса на переданном уровне MultiIndex
.
fill_value=nan
- значение, используемое для отсутствующих значений. По умолчанию NaN
, но может быть любым "совместимым" значением.
limit=None
- максимальное количество последовательных элементов для method='ffill'
или method='backfill'
заполнения.
tolerance=None
- максимальное расстояние между исходной и новой метками для неточного совпадения. Значения индекса в совпадающих местоположениях удовлетворяют уравнению abs(index[indexer] - target) <= tolerance
.
Значение аргумента tolerance
может быть скалярным, которое применяет один и тот же допуск ко всем значениям, или объектом list-like
, который применяет переменный допуск к каждому элементу. List-like
объект включает список, кортеж, массив, серию и должен быть того же размера, что и индекс, а его dtype
должен точно соответствовать типу индекса.
DataFrame.reindex()
возвращает DataFrame
с измененным индексом.Series.reindex()
возвращает Series
с измененным индексом..reindex()
объектов DataFrame
/Series
Методы DataFrame.reindex()
и Series.reindex()
модуля pandas
приводит DataFrame
/Series
соответственно в соответствии с новым индексом с дополнительной логикой заполнения.
Методы размещают NA
/NaN
в местоположениях, не имеющих значения в предыдущем индексе. Если новый индекс НЕ эквивалентен текущему и если аргумент copy=False
, то создается новый объект.
И так, метод .reindex()
является фундаментальным методом выравнивания данных в Pandas. Он используется для реализации почти всех других функций, основанных на функциональности выравнивания индексных меток. Повторная индексация означает согласование данных с заданным набором меток вдоль определенной оси. Это позволяет достичь нескольких целей:
NA
) в места записей, где не существовало данных для этой меткиПростой пример:
>>> import pandas as pd >>> import numpy as np >>> s = pd.Series(np.random.randn(5), index=["a", "b", "c", "d", "e"]) >>> s # a 0.458235 # b -0.886856 # c -1.757924 # d -0.481370 # e 0.993616 # dtype: float64 >>> s.reindex(["e", "b", "f", "d"]) # e 0.993616 # b -0.886856 # f NaN # d -0.481370 # dtype: float64
Здесь метка f
не содержалась в исходной Series
и, следовательно, в результате заполнилась NaN
.
С помощью DataFrame
можно одновременно переиндексировать индекс и столбцы:
df = pd.DataFrame( { "one": pd.Series(np.random.randn(3), index=["a", "b", "c"]), "two": pd.Series(np.random.randn(4), index=["a", "b", "c", "d"]), "three": pd.Series(np.random.randn(3), index=["b", "c", "d"]), } ) >>> df # one two three # a 0.782362 -0.318496 NaN # b -1.332115 0.363552 -0.481942 # c -0.241576 -1.004899 1.792289 # d NaN 0.113503 0.648034 >>> df.reindex(index=["c", "f", "b"], columns=["three", "two", "one"]) # three two one # c 1.792289 -1.004899 -0.241576 # f NaN NaN NaN # b -0.481942 0.363552 -1.332115
Обратите внимание, что объекты Index
, содержащие фактические метки осей, могут быть общими для всех объектов. Таким образом, если есть Series
и DataFrame
, то можно сделать следующее:
>>> rs = s.reindex(df.index) >>> rs # a 0.458235 # b -0.886856 # c -1.757924 # d -0.481370 # dtype: float64 >>> rs.index is df.index # True
Это означает, что индекс переиндексированного Series
является тем же объектом Python, что и индекс DataFrame
.
DataFrame.reindex()
также поддерживает соглашение о вызовах в стиле axis
, где указывается один аргумент labels
и ось axis
, к которой он относится.
>>> df.reindex(["c", "f", "b"], axis="index") # one two three # c -0.241576 -1.004899 1.792289 # f NaN NaN NaN # b -1.332115 0.363552 -0.481942 >>> df.reindex(["three", "two", "one"], axis="columns") # three two one # a NaN -0.318496 0.782362 # b -0.481942 0.363552 -1.332115 # c 1.792289 -1.004899 -0.241576 # d 0.648034 0.113503 NaN
Заметка. При написании кода, чувствительного к производительности, следует учитывать, что многие операции выполняются быстрее с предварительно выровненными данными. При добавлении двух невыровненных
DataFrames
внутренне запускается шаг переиндексации. Для исследовательского анализа разница вряд ли будет заметна (т.к. переиндексация была сильно оптимизирована), но когда циклы ЦП имеют значение, то несколько явных вызовов повторной индексации здесь и там могут оказать влияние.
Можно взять объект и переиндексировать его оси так, чтобы они были помечены так же, как и другой объект. Несмотря на то, что синтаксис для этого прост, хотя и многословен, это достаточно распространенная операция, поэтому для упрощения этой операции доступен метод .reindex_like()
:
>>> df2 = df.reindex(["a", "b", "c"], columns=["one", "two"]) >>> df.reindex_like(df2) # one two # a 0.782362 -0.318496 # b -1.332115 0.363552 # c -0.241576 -1.004899
Метод .reindex()
принимает необязательный аргумент method
, который является методом заполнения:
Принимаемые значения:
pad
/ffill
- заполнение значений впередbfill
/backfill
- заполнение значений в обратном направленииnearest
- заполнение от ближайшего значения индексаЭти методы требуют, чтобы индексы были упорядочены в порядке увеличения или уменьшения.
Смотрим поведение этих методы заполнения на Series
:
>>> rng = pd.date_range("1/3/2000", periods=8) >>> ts = pd.Series(np.random.randn(8), index=rng) >>> ts2 = ts.iloc[[0, 3, 6]] >>> ts # 2000-01-03 -0.553267 # 2000-01-04 0.715464 # 2000-01-05 0.020540 # 2000-01-06 -0.309617 # 2000-01-07 1.163681 # 2000-01-08 -0.963053 # 2000-01-09 0.883835 # 2000-01-10 -2.165508 # Freq: D, dtype: float64 >>> ts2 # 2000-01-03 -0.553267 # 2000-01-06 -0.309617 # 2000-01-09 0.883835 # Freq: 3D, dtype: float64 >>> ts2.reindex(ts.index) # 2000-01-03 -0.553267 # 2000-01-04 NaN # 2000-01-05 NaN # 2000-01-06 -0.309617 # 2000-01-07 NaN # 2000-01-08 NaN # 2000-01-09 0.883835 # 2000-01-10 NaN # Freq: D, dtype: float64 >>> ts2.reindex(ts.index, method="ffill") # 2000-01-03 -0.553267 # 2000-01-04 -0.553267 # 2000-01-05 -0.553267 # 2000-01-06 -0.309617 # 2000-01-07 -0.309617 # 2000-01-08 -0.309617 # 2000-01-09 0.883835 # 2000-01-10 0.883835 # Freq: D, dtype: float64 >>> ts2.reindex(ts.index, method="bfill") # 2000-01-03 -0.553267 # 2000-01-04 -0.309617 # 2000-01-05 -0.309617 # 2000-01-06 -0.309617 # 2000-01-07 0.883835 # 2000-01-08 0.883835 # 2000-01-09 0.883835 # 2000-01-10 NaN # Freq: D, dtype: float64 >>> ts2.reindex(ts.index, method="nearest") # 2000-01-03 -0.553267 # 2000-01-04 -0.553267 # 2000-01-05 -0.309617 # 2000-01-06 -0.309617 # 2000-01-07 -0.309617 # 2000-01-08 0.883835 # 2000-01-09 0.883835 # 2000-01-10 0.883835 # Freq: D, dtype: float64
Обратите внимание, что тот же результат можно было бы получить с помощью метода .ffill()
(за исключением method='nearest'
) или интерполяции
:
>>> ts2.reindex(ts.index).ffill() # 2000-01-03 -0.553267 # 2000-01-04 -0.553267 # 2000-01-05 -0.553267 # 2000-01-06 -0.309617 # 2000-01-07 -0.309617 # 2000-01-08 -0.309617 # 2000-01-09 0.883835 # 2000-01-10 0.883835 # Freq: D, dtype: float64
Аргументы limit
и tolerance
обеспечивают дополнительный контроль над заполнением при повторной индексации. Лимит определяет максимальное количество последовательных совпадений:
>>> ts2.reindex(ts.index, method="ffill", limit=1) # 2000-01-03 -0.553267 # 2000-01-04 -0.553267 # 2000-01-05 NaN # 2000-01-06 -0.309617 # 2000-01-07 -0.309617 # 2000-01-08 NaN # 2000-01-09 0.883835 # 2000-01-10 0.883835 # Freq: D, dtype: float64
Напротив, аргумент tolerance
задает максимальное расстояние между значениями индекса и индексатора:
>>> ts2.reindex(ts.index, method="ffill", tolerance="1 day") # 2000-01-03 -0.553267 # 2000-01-04 -0.553267 # 2000-01-05 NaN # 2000-01-06 -0.309617 # 2000-01-07 -0.309617 # 2000-01-08 NaN # 2000-01-09 0.883835 # 2000-01-10 0.883835 # Freq: D, dtype: float64
Обратите внимание, что при использовании для pandas.DatetimeIndex
, pandas.TimedeltaIndex
или pandas.PeriodIndex
аргумент tolerance
будет приведен к pandas.Timedelta
, если это возможно. Это позволяет указать допуск с соответствующими строками.
DataFrame.reindex()
Метод DataFrame.reindex()
поддерживает два соглашения о вызовах:
DataFrame.reindex(index=index_labels, columns=column_labels, ...)
;DataFrame.reindex(labels, axis={'index', 'columns'}, ...)
.Настоятельно рекомендуется использовать ключевые аргументы, для ясности намерений.
Для большинства примеров будем использовать фрейм данных следующего вида:
>>> import pandas as pd >>> index = ['Firefox', 'Chrome', 'Safari', 'IE10', 'Konqueror'] df = pd.DataFrame({'http_status': [200, 200, 404, 404, 301], 'response_time': [0.04, 0.02, 0.07, 0.08, 1.0]}, index=index) >>> df # http_status response_time # Firefox 200 0.04 # Chrome 200 0.02 # Safari 404 0.07 # IE10 404 0.08 # Konqueror 301 1.00
Создаем новый индекс и переиндексируем DataFrame
. По умолчанию, значениям в новом индексе, не имеющим соответствующих записей в кадре данных, присваивается значение NaN
.
>>> new_index = ['Safari', 'Iceweasel', 'Comodo Dragon', 'IE10', 'Chrome'] >>> df.reindex(new_index) # http_status response_time # Safari 404.0 0.07 # Iceweasel NaN NaN # Comodo Dragon NaN NaN # IE10 404.0 0.08 # Chrome 200.0 0.02
Можно восполнить пропущенные значения, передав значение ключевому аргументу fill_value
. Так как индекс не увеличивается и не уменьшается, следовательно нельзя использовать ключевой аргумент method
для заполнения значений NaN
.
>>> df.reindex(new_index, fill_value=0) # http_status response_time # Safari 404 0.07 # Iceweasel 0 0.00 # Comodo Dragon 0 0.00 # IE10 404 0.08 # Chrome 200 0.02 >>> df.reindex(new_index, fill_value='missing') # http_status response_time # Safari 404 0.07 # Iceweasel missing missing # Comodo Dragon missing missing # IE10 404 0.08 # Chrome 200 0.02
Также можно переиндексировать столбцы.
>>> df.reindex(columns=['http_status', 'user_agent']) # http_status user_agent # Firefox 200 NaN # Chrome 200 NaN # Safari 404 NaN # IE10 404 NaN # Konqueror 301 NaN
Или можно использовать ключевой аргумент axis="columns"
.
>>> df.reindex(['http_status', 'user_agent'], axis="columns") # http_status user_agent # Firefox 200 NaN # Chrome 200 NaN # Safari 404 NaN # IE10 404 NaN # Konqueror 301 NaN
Чтобы дополнительно показать функциональность заполнения отсутствующих значений в переиндексации, создадим DataFrame
с монотонно увеличивающимся индексом (например, последовательность дат).
>>> date_index = pd.date_range('1/1/2010', periods=6, freq='D') df2 = pd.DataFrame({"prices": [100, 101, np.nan, 100, 89, 88]}, index=date_index) >>> df2 # prices # 2024-01-01 100.0 # 2024-01-02 101.0 # 2024-01-03 NaN # 2024-01-04 100.0 # 2024-01-05 89.0 # 2024-01-06 88.0
Предположим, что нужно расширить фрейм данных, чтобы охватить более широкий диапазон дат.
# создадим новый индекс >>> date_index2 = pd.date_range('12/29/2009', periods=10, freq='D') # переиндексируем >>> df2.reindex(date_index2) # prices # 2023-12-29 NaN # 2023-12-30 NaN # 2023-12-31 NaN # 2024-01-01 100.0 # 2024-01-02 101.0 # 2024-01-03 NaN # 2024-01-04 100.0 # 2024-01-05 89.0 # 2024-01-06 88.0 # 2024-01-07 NaN
Записи индекса, которые не имели значения в исходном фрейме данных (например, '2023-12-29'), по умолчанию заполняются NaN
. При желании можно заполнить недостающие значения, используя один из нескольких вариантов.
Например, чтобы распространить последнее допустимое значение для заполнения значений NaN
, используем аргумент method
со значением bfill
.
>>> df2.reindex(date_index2, method='bfill') # prices # 2009-12-29 100.0 # 2009-12-30 100.0 # 2009-12-31 100.0 # 2010-01-01 100.0 # 2010-01-02 101.0 # 2010-01-03 NaN # 2010-01-04 100.0 # 2010-01-05 89.0 # 2010-01-06 88.0 # 2010-01-07 NaN
Обратите внимание, что значение NaN
, присутствующее в исходном DataFrame
(при значении индекса 2024-01-03), не будет заполнено ни одной из схем распространения значений. Это связано с тем, что заполнение при повторной индексации не рассматривает значения исходного DataFrame
, а только сравнивает исходный и требуемый индексы. Если необходимо заполнить значения NaN
, присутствующие в исходном DataFrame
, необходимо использовать метод DataFrame.fillna()
.