2025, Dec 12 03:02

Нормализуем Delivery Period в pandas: диапазон в месяцы Month Year

Пошагово нормализуем столбец Delivery Period в pandas: распознаем диапазон дат, генерируем месяцы period_range, применяем explode и форматируем в вид Month Year

Приведите к единому виду смешанный столбец “Delivery Period”: разверните один строковый диапазон вроде “2025-01-01 to 2025-12-31” в отдельные строки по одному месяцу и сохраните уже заданные значения формата месяц–год без изменений. Ниже — компактный подход на pandas: он обнаруживает диапазон, генерирует месячные периоды, «взрывает» их в строки и форматирует результат в ожидаемый вид “Month Year”.

Задача

Часть строк хранит период поставки как строку с датами начала и конца вместо требуемого формата “Month Year”. Нужно найти такие строки и преобразовать каждую в несколько строк — по одной на каждый месяц диапазона — при этом остальные столбцы должны оставаться без изменений.

Воспроизводимый пример

Входные данные содержат один годовой диапазон и несколько значений уже в нормализованном виде «месяц‑год».

import pandas as pd
seed_cols = {
    'Price Curve': [
        'TEST',
        'some curve',
        'some curve',
        'some curve',
        'some curve',
        'some curve',
        'some curve',
        'some curve'
    ],
    'Text': [
        'TEST',
        'some text',
        'some text',
        'some text',
        'some text',
        'some text',
        'some text',
        'some text'
    ],
    'Delivery Period': [
        '2025-01-01 to 2025-12-31',
        'June 2025',
        'July 2025',
        'August 2025',
        'September 2025',
        'October 2025',
        'November 2025',
        'December 2025'
    ]
}
frame = pd.DataFrame(seed_cols)

Что происходит и зачем

В столбце смешаны два представления времени: единая строка «от начала до конца», охватывающая несколько месяцев, и отдельные строки в формате “Month Year”. Чтобы выровнять модель данных, диапазон нужно превратить в месячную последовательность и развернуть в отдельные строки. Самый простой надежный признак — подстрока, разделяющая границы диапазона.

Решение

Стратегия такова: определить строки с диапазоном, разделить границы, построить месячную последовательность, развернуть последовательность в строки, отформатировать результат как “Month Year”, а затем вернуть значения в исходный столбец.

# Определяем строки, содержащие диапазон дат
has_span = frame['Delivery Period'].str.contains(' to ')
# Разбиваем текстовый диапазон на начало/конец и генерируем месячные периоды
frame.loc[has_span, 'span_seq'] = frame.loc[has_span, 'Delivery Period'].str.split(' to ')
frame.loc[has_span, 'span_seq'] = frame.loc[has_span, 'span_seq'].transform(
    lambda pair: pd.period_range(pair[0], pair[1], freq='M')
)
# Разворачиваем по строке на период и форматируем как "Month Year"
frame = frame.explode('span_seq')
frame['span_seq'] = frame['span_seq'].dt.strftime('%B %Y')
# Если есть развернутое значение — берем его, иначе оставляем исходное
frame['Delivery Period'] = frame['span_seq'].combine_first(frame['Delivery Period'])
# Удаляем временный вспомогательный столбец
frame = frame.drop(columns='span_seq')

Почему это важно

Единая логика времени в поле “Delivery Period” упрощает дальнейшую обработку. Когда каждому месяцу соответствует своя строка, последующие шаги работают с ожидаемым форматом и совпадают с образцом результата, избегая неоднозначности, возникающей из-за одного широкого строкового диапазона.

Итоги

Легко выявляйте диапазон, преобразуйте его в месячную последовательность и разворачивайте строки. Связка генерации периодов, explode и финального форматирования дает чистый, единообразный столбец “Month Year”, не затрагивая строки, которые уже были оформлены корректно.