2025, Dec 05 18:02
Интерполяция почасового ряда в pandas без длинных разрывов
Как разбить временной ряд по разрывам и интерполировать только внутри сегментов: pandas, resample и interpolate для почасовых данных без ложных заполнений.
Когда вы ресемплируете временной ряд до почасовой частоты, интерполяция — удобный способ заполнить пропущенные метки времени. Загвоздка возникает, когда разрывы слишком велики и вам не хочется «дорисовывать» значения через длинные промежутки. Цель — разбить данные на непрерывные почасовые сегменты, интерполировать только внутри каждого смежного блока и оставить крупные паузы как границы между сегментами.
Постановка задачи
Представьте DataFrame с временным индексом, в котором отсутствуют отдельные часы. Наивная связка resample плюс interpolate заполняет каждую дырку, включая большие. Например:
frame = frame.resample('1h').first()
frame = frame.interpolate(method='time')
frame
В итоге получаются почасовые значения на всём промежутке — даже поверх многочасовых провалов, чего, вероятно, лучше избегать.
Почему так происходит
Ресемплинг формирует регулярный почасовой индекс, а интерполяция по времени рассчитывает значения между ближайшими известными точками, опираясь на их метки времени. По своей природе она не знает, что четырех- или пятичасовой разрыв следует считать границей. Если правило гласит «не интерполировать через разрывы длиннее 3 часов», сначала нужно обнаружить такие промежутки и интерполировать только внутри непрерывных участков.
Стратегия: разделить по крупным разрывам, затем ресемплировать и интерполировать внутри каждой части
Разница индекса между соседними строками показывает места больших скачков. Посчитайте разность последовательных меток времени, сравните её с выбранным порогом и накапливайте группы с помощью скользящей суммы. Каждая такая группа — непрерывный сегмент. Ресемплируйте и интерполируйте по сегментам, заполняя лишь короткие пробелы.
Полное решение
Ниже приведён фрагмент, который создаёт сегменты на разрывах строго больше трёх часов и возвращает либо словарь почасовых DataFrame после интерполяции, либо список, который можно позже склеить.
limit = pd.Timedelta(hours=3)
markers = (frame.index.diff() > limit)
parts_map = {f'part{ix}': chunk.resample('1h').first().interpolate(method='time')
for ix, (grp, chunk) in enumerate(frame.groupby(markers.cumsum()))}
Если удобнее получить список и затем объединить его обратно:
segments = [chunk.resample('1h').first().interpolate(method='time')
for grp, chunk in frame.groupby(markers.cumsum())]
Это даёт ожидаемые три сегмента для примерных данных — теперь с почасовым шагом и интерполяцией только внутри непрерывных блоков:
{'part0': A
2023-03-18 05:00:00 3.0
2023-03-18 06:00:00 4.0
2023-03-18 07:00:00 24.4,
'part1': A
2023-03-18 12:00:00 5.60
2023-03-18 13:00:00 3.40
2023-03-18 14:00:00 3.95
2023-03-18 15:00:00 4.50,
'part2': A
2023-03-18 20:00:00 8.8
2023-03-18 21:00:00 3.2}
Как работает группировка
Идея проста. Разность индекса подсвечивает места, где разрывы превышают порог. Преобразование этих булевых меток в группы через накопленную сумму даёт непрерывные ярлыки, которые можно передать в groupby. Внутри каждой группы временные метки достаточно близки, чтобы после ресемплинга оправданно интерполировать. Между группами интерполяции нет — граница сохраняется за счёт сегментации.
Почему это стоит знать
Приведение временных рядов к регулярной сетке — частый шаг подготовки для моделирования, мониторинга и аналитики. Бездумная интерполяция через длительные простои или провалы сбора может породить вводящие в заблуждение артефакты. Сегментация по размеру разрыва позволяет сохранить удобство resample и interpolate, одновременно соблюдая требования к качеству данных. К тому же упрощается последующая логика: каждый сегмент — это аккуратный, выровненный по часам блок с реалистичными заполнениями.
Практические рекомендации
Находите большие скачки через index.diff и сравнение с порогом Timedelta. Превратите эти скачки в метки непрерывных групп с помощью cumsum. Применяйте resample и интерполяцию по времени только внутри каждой группы. Если затем нужно собрать серию обратно, храните список и конкатенируйте позже; если требуются отдельные артефакты — храните словарь с ключами по индексу сегмента. Такой подход делает интерполяцию честной, а почасовые данные — надёжными.