Объект
pandas.IntervalIndex()
представляет собой тип индекса, который полезен для поддержки индексации значений, которые будут соответствовать набору ограниченных интервалов. Это контейнер вокруг объектовpandas.Interval()
.
pandas.Interval
- представляет собой ограниченный интервал, подобный срезу;pandas.IntervalIndex
- контейнер вокруг элементов Interval
;pandas.interval_range()
создает IntervalIndex
фиксированной частоты.pandas.Interval(left, right, closed='right')
:Объект pandas.Interval()
представляет собой ограниченный интервал (неизменяемый объект), подобный срезу, где аргументы left
и right
- границы интервала, а closed
отвечает за закрытие границ (принимает значения 'left'
, 'right'
, 'both'
, 'neither'
)
Аргументы left
и right
должны быть одного типа, должны иметь возможность операций сравнивания, а также должны удовлетворять условию left <= right
.
Замкнутый интервал (в математике обозначаемый квадратными скобками) содержит свои конечные точки, т. е. замкнутый интервал [0, 5]
характеризуется условиями 0 <= x <= 5
. Это то, что означает closed='both'
. Открытый интервал (в математике обозначаемый круглыми скобками) не содержит своих конечных точек, т. е. открытый интервал (0, 5)
характеризуется условиями 0 < x < 5
. Это то, что означает closed='neither'
. Интервалы также могут быть полуоткрытыми или полузакрытыми, т.е. [0, 5)
описывается 0 <= x < 5
(closed='left'
), а (0, 5]
описывается 0 < x <= 5
(closed='right'
).
Можно создать интервалы разных типов, например, числовые:
>>> import pandas as pd >>> iv = pd.Interval(left=0, right=5) >>> iv # Interval(0, 5, closed='right') # принадлежность к интервалу >>> 2.5 in iv # True >>> pd.Interval(left=2, right=5, closed='both') in iv # True
Можно проверить границы (closed='right'
, как 0 < x <= 5
):
>>> 0 in iv # False >>> 5 in iv # True >>> 0.0001 in iv # True # длина интервала >>> iv.length # 5
С интервалом можно производить сложение +
и умножение *
, и операция применяется к каждой из его границ, поэтому результат зависит от типа связанных элементов.
>>> shifted_iv = iv + 3 >>> shifted_iv # Interval(3, 8, closed='right') >>> extended_iv = iv * 10.0 >>> extended_iv # Interval(0.0, 50.0, closed='right')
Чтобы создать временной интервал, можно использовать временные метки в качестве границ
year = pd.Interval(pd.Timestamp('2023-01-01 00:00:00'), pd.Timestamp('2024-01-01 00:00:00'), closed='left') >>> pd.Timestamp('2023-10-10 00:00') in year # True >>> year.length # Timedelta('365 days 00:00:00')
pandas.IntervalIndex(data, closed=None, dtype=None, copy=False, name=None, verify_integrity=True)
:Объект pandas.IntervalIndex
вместе со своим собственным типом IntervalDtype
, а также скалярным типом pandas.Interval()
обеспечивает первоклассную поддержку записи интервалов.
Объект pandas.IntervalIndex
допускает некоторую уникальную индексацию, а также используется в качестве возвращаемого типа для категорий в функциях pandas.cut()
и pandas.qcut()
.
Новый индекс
pandas.IntervalIndex
обычно создается с помощью функцииpandas.interval_range()
. Его также можно создать с помощью одного из методов конструктора:
IntervalIndex.from_arrays(left, right, closed='right', name=None, dtype=None)
,>>> import pandas as pd >>> pd.IntervalIndex.from_arrays([0, 1, 2], [1, 2, 3]) # IntervalIndex([(0, 1], (1, 2], (2, 3]], # dtype='interval[int64, right]')
IntervalIndex.from_breaks(breaks, closed='right', name=None, copy=False, dtype=None)
,>>> pd.IntervalIndex.from_breaks([0, 1, 2, 3]) # IntervalIndex([(0, 1], (1, 2], (2, 3]], # dtype='interval[int64, right]')
IntervalIndex.from_tuples(data, closed='right', name=None, copy=False, dtype=None)
.>>> pd.IntervalIndex.from_tuples([(0, 1), (1, 2)]) # IntervalIndex([(0, 1], (1, 2]], # dtype='interval[int64, right]')
IntervalIndex
Объект pandas.IntervalIndex
можно использовать в DataFrame
и Series
в качестве индекса.
df = pd.DataFrame( {"A": [1, 2, 3, 4]}, index=pd.IntervalIndex.from_breaks([0, 1, 2, 3, 4]) ) >>> df # A # (0, 1] 1 # (1, 2] 2 # (2, 3] 3 # (3, 4] 4
Индексирование на основе меток через .loc по краям интервала работает так, как и ожидается.
>>> df.loc[2] # A 2 # Name: (1, 2], dtype: int64 >>> df.loc[[2, 3]] # A # (1, 2] 2 # (2, 3] 3
Если выбрать метку, которая находится внутри интервала, то это также выберет интервал.
>>> df.loc[2.5] # A 3 # Name: (2, 3], dtype: int64 >>> df.loc[[2.5, 3.5]] # A # (2, 3] 3 # (3, 4] 4
Выбор данных с использованием класса Interval()
вернет только точные совпадения.
>>> df.loc[pd.Interval(1, 2)] # A 2 # Name: (1, 2], dtype: int64
Попытка выбрать интервал, который не содержится в IntervalIndex
, вызовет ошибку KeyError
.
>>> df.loc[pd.Interval(0.5, 2.5)] # Traceback (most recent call last): # ... # KeyError: Interval(0.5, 2.5, closed='right')
Выбор всех интервалов, перекрывающих имеющийся интервал, можно выполнить с помощью метода IntervalIndex.overlaps()
для создания логического индексатора.
>>> idxr = df.index.overlaps(pd.Interval(0.5, 2.5)) >>> idxr # array([ True, True, True, False])
Функции pandas.cut()
и pandas.qcut()
возвращают объект Categorical
, а созданные ими интервалы сохраняются как IntervalIndex
в его атрибуте .categories
.
# сгенерируем интервалы >>> c = pd.cut(range(4), bins=2) >>> c # [(-0.003, 1.5], (-0.003, 1.5], (1.5, 3.0], (1.5, 3.0]] # Categories (2, interval[float64, right]): [(-0.003, 1.5] < (1.5, 3.0]] >>> c.categories # IntervalIndex([(-0.003, 1.5], (1.5, 3.0]], dtype='interval[float64, right]')
Функция pandas.cut()
может принимать IntervalIndex()
в качестве аргумента bins
, это позволяет использовать полезную идиому pandas
. Чтобы сгенерировать интервалы, сначала нужно вызвать функцию pandas.cut()
с некоторыми данными и интервалами, установленными на фиксированное число. Затем, при последующих вызовах функции pandas.cut()
необходимо передать значения атрибута .categories
в качестве аргумента bins
.
# аргументу `bins` передаем категории, сгенерированные ранее >>> pd.cut([0, 3, 5, 1], bins=c.categories) # [(-0.003, 1.5], (1.5, 3.0], NaN, (-0.003, 1.5]] # Categories (2, interval[float64, right]): [(-0.003, 1.5] < (1.5, 3.0]]
Любому значению, которое выходит за пределы имеющихся интервалов, будет присвоено значение NaN
.
Если необходимы интервалы с постоянной частотой, то для создания IntervalIndex
можно использовать функцию pandas.interval_range()
, используя различные комбинации аргументов start
, end
, и periods
. Частота по умолчанию для числовых интервалов - 1, а для интервалов, подобных дате и времени, один календарный день:
>>> pd.interval_range(start=0, end=5) # IntervalIndex([(0, 1], (1, 2], (2, 3], (3, 4], (4, 5]], dtype='interval[int64, right]') >>> pd.interval_range(start=pd.Timestamp("2017-01-01"), periods=4) # IntervalIndex([(2017-01-01, 2017-01-02], (2017-01-02, 2017-01-03], (2017-01-03, 2017-01-04], # (2017-01-04, 2017-01-05]], dtype='interval[datetime64[ns], right]') >>> pd.interval_range(end=pd.Timedelta("3 days"), periods=3) # IntervalIndex([(0 days 00:00:00, 1 days 00:00:00], (1 days 00:00:00, 2 days 00:00:00], # (2 days 00:00:00, 3 days 00:00:00]], dtype='interval[timedelta64[ns], right]')
Аргумент freq
функции pandas.interval_range()
может использоваться для указания частот, отличных от значений по умолчанию, и может использовать различные псевдонимы частот с интервалами, подобными дате и времени:
>>> pd.interval_range(start=0, periods=5, freq=1.5) # IntervalIndex([(0.0, 1.5], (1.5, 3.0], (3.0, 4.5], (4.5, 6.0], # (6.0, 7.5]], dtype='interval[float64, right]') >>> pd.interval_range(start=pd.Timestamp("2017-01-01"), periods=4, freq="W") # IntervalIndex([(2017-01-01, 2017-01-08], (2017-01-08, 2017-01-15], # (2017-01-15, 2017-01-22], (2017-01-22, 2017-01-29]], dtype='interval[datetime64[ns], right]') >>> pd.interval_range(start=pd.Timedelta("0 days"), periods=3, freq="9H") # IntervalIndex([(0 days 00:00:00, 0 days 09:00:00], (0 days 09:00:00, 0 days 18:00:00], # (0 days 18:00:00, 1 days 03:00:00]], dtype='interval[timedelta64[ns], right]')
Кроме того, можно использовать аргумент closed
(принимает значения 'left'
, 'right'
, 'both'
, 'neither'
) для указания того, с какой стороны (сторон) интервалы закрыты. По умолчанию интервалы закрыты с правой стороны.
>>> pd.interval_range(start=0, end=4, closed="both") # IntervalIndex([[0, 1], [1, 2], [2, 3], [3, 4]], dtype='interval[int64, both]') >>> pd.interval_range(start=0, end=4, closed="neither") # IntervalIndex([(0, 1), (1, 2), (2, 3), (3, 4)], dtype='interval[int64, neither]')
При указании start
, end
и periods
будет создан диапазон равномерно распределенных интервалов от начала до конца включительно с количеством элементов periods
в результирующем индексе IntervalIndex
:
>>> pd.interval_range(start=0, end=6, periods=4) # IntervalIndex([(0.0, 1.5], (1.5, 3.0], (3.0, 4.5], (4.5, 6.0]], dtype='interval[float64, right]') >>> pd.interval_range(pd.Timestamp("2018-01-01"), pd.Timestamp("2018-02-28"), periods=3) # IntervalIndex([(2018-01-01, 2018-01-20 08:00:00], (2018-01-20 08:00:00, 2018-02-08 16:00:00], # (2018-02-08 16:00:00, 2018-02-28]], dtype='interval[datetime64[ns], right]')