Сдвиги и признаки запаздывания
Создавайте столбцы с запаздыванием и опережением с помощью shift(), вычисляйте изменение между периодами с помощью diff() и рассчитывайте процентное изменение.
«Сдвиги и признаки запаздывания» — бесплатный урок Pandas & NumPy Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Pandas & NumPy Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Pandas & NumPy Academy содержит 4 уроков всего.
Почему важны признаки с запаздыванием
В анализе временных рядов значение на предыдущем временном шаге (запаздывание) часто является одним из лучших предикторов текущего значения. Например, вчерашние продажи помогают предсказать сегодняшние. Создание столбцов с запаздыванием позволяет использовать исторические значения как признаки в моделях машинного обучения или при статистическом анализе автокорреляции. Pandas предоставляет shift() для создания таких признаков одним векторизованным вызовом.
shift(): перемещение значений вперёд или назад
Series.shift(n) перемещает все значения вниз на n позиций (положительное n создаёт запаздывание), заполняя первые n строк значением NaN. Передача отрицательного n перемещает значения вверх (создаёт опережение, сдвигая будущие значения назад к текущей строке). Индекс остаётся неизменным — перемещаются только значения.
import pandas as pd
import numpy as np
df = pd.DataFrame(
{'sales': [100, 120, 115, 130, 140, 125]},
index=pd.date_range('2024-01-01', periods=6, freq='D')
)
# Lag-1: yesterday's sales
df['sales_lag1'] = df['sales'].shift(1)
# Lead-1: tomorrow's sales (shifted up)
df['sales_lead1'] = df['sales'].shift(-1)
print(df)Создание нескольких столбцов с запаздыванием
Для машинного обучения обычно создают сразу несколько признаков с запаздыванием — сдвиг на 1, на 7 (тот же день на прошлой неделе) и на 30 (тот же день в прошлом месяце). Наиболее понятный способ — создать их в цикле и присвоить каждый новому столбцу. В результирующем DataFrame исходный ряд дополнен всеми его версиями со сдвигом и готов к построению моделей.
for lag in [1, 2, 3, 7]:
df[f'sales_lag{lag}'] = df['sales'].shift(lag)
print(df.columns.tolist())
# ['sales', 'sales_lag1', 'sales_lag2', 'sales_lag3', 'sales_lag7']
# Drop rows with NaN from the largest lag period
df_model = df.dropna()
print('Ready for modelling, shape:', df_model.shape)shift() с freq для сдвига по времени
Вместо сдвига на целое число строк можно сдвигать данные на временное смещение с помощью параметра freq. df.shift(1, freq='ME') сдвигает индекс вперёд на один конец месяца, оставляя значения на месте, но изменяя индекс. Это удобно для выравнивания двух временных рядов, смещённых на фиксированный период, без перестановки значений.
monthly = pd.Series(
[100, 120, 115],
index=pd.date_range('2024-01-31', periods=3, freq='ME')
)
# Shift the index forward by 1 month (values stay, index moves)
shifted_index = monthly.shift(1, freq='ME')
print('Original index:', monthly.index.tolist())
print('Shifted index: ', shifted_index.index.tolist())
# Original: [2024-01-31, 2024-02-29, 2024-03-31]
# Shifted: [2024-02-29, 2024-03-31, 2024-04-30]diff(): изменение от периода к периоду
Series.diff(n) вычисляет разность между значением и значением, расположенным на n позиций раньше: x[t] - x[t-n]. Это часто используют для вычисления изменений день к дню, различий неделя к неделе или изменений год к году. Первые n строк содержат NaN, поскольку предыдущих значений, из которых можно было бы вычесть текущие, нет.
df['sales_diff1'] = df['sales'].diff(1) # day-over-day change
df['sales_diff7'] = df['sales'].diff(7) # week-over-week change
print(df[['sales', 'sales_diff1']].head())
# sales sales_diff1
# 2024-01-01 100 NaN
# 2024-01-02 120 20.0 <- +20 from yesterday
# 2024-01-03 115 -5.0 <- -5 from yesterdaypct_change(): процентное изменение
Series.pct_change(n) вычисляет относительное процентное изменение: (x[t] - x[t-n]) / x[t-n]. Это необходимо для финансового анализа (дневная доходность), вычисления темпов роста и любых ситуаций, в которых относительное изменение важнее абсолютного. Умножьте результат на 100, чтобы получить процентные пункты.
df['pct_chg'] = df['sales'].pct_change().round(3)
df['pct_chg_7d'] = df['sales'].pct_change(7).round(3)
print(df[['sales', 'pct_chg']].head())
# sales pct_chg
# 2024-01-01 100 NaN
# 2024-01-02 120 0.200 <- 20% increase
# 2024-01-03 115 -0.042 <- 4.2% decreaseОбъединение shift() с арифметикой
Вы можете объединять shift() с арифметическими операциями для вычисления производных признаков времени. Например, можно получить отношение сегодняшнего значения к значению прошлой недели, накопительную сумму с фиксированного начала или разность с прошлогодним значением. Все эти операции следуют одному шаблону: сдвиньте исходный ряд и выполните поэлементную арифметику с текущими значениями.
# Week-over-week growth index (today / last week)
df['wow_ratio'] = (df['sales'] / df['sales'].shift(7)).round(3)
# Deviation from 3-day lag
df['dev_3d'] = df['sales'] - df['sales'].shift(3)
# Is today higher than yesterday? (boolean feature)
df['higher_than_yesterday'] = df['sales'] > df['sales'].shift(1)
print(df[['sales', 'wow_ratio', 'higher_than_yesterday']].head())cumsum() и cumprod() для накопительных признаков
Series.cumsum() вычисляет текущую сумму от первой строки до каждой строки, а Series.cumprod() — накопительное произведение. Это удобно для накопительной выручки, накопительной доходности (сложного роста) и итогов с начала года. Аргументы не требуются; методы работают с любым числовым Series или столбцом DataFrame.
# Cumulative sales (year-to-date total)
df['ytd_sales'] = df['sales'].cumsum()
# Cumulative product: compound growth factor
returns = pd.Series([0.02, -0.01, 0.03, 0.01, -0.005])
df_ret = pd.DataFrame({'daily_return': returns})
df_ret['compound'] = (1 + df_ret['daily_return']).cumprod() - 1
print(df_ret)Признаки с запаздыванием для машинного обучения
При подготовке временных рядов для машинного обучения стандартный этап создания признаков — построение матрицы лаговых признаков. Каждый столбец представляет целевую переменную на отдельном шаге в прошлом. После создания лагов удалите строки с NaN (они появляются в начале из-за отсутствия предыдущих данных) и разделите данные на обучающую и тестовую выборки без перемешивания, сохраняя временной порядок.
def make_lag_matrix(series, n_lags):
df_lags = pd.DataFrame({'y': series})
for lag in range(1, n_lags + 1):
df_lags[f'lag_{lag}'] = series.shift(lag)
return df_lags.dropna()
lag_df = make_lag_matrix(df['sales'], n_lags=3)
print(lag_df)
# y lag_1 lag_2 lag_3
# ... ... ... ...Сдвиг внутри групп
Если данные содержат несколько объектов (например, несколько товаров или регионов в одном DataFrame), необходимо вычислять сдвиги отдельно внутри группы каждого объекта. Используйте groupby().shift(), чтобы лаг для первой строки товара A был равен NaN, а не последнему значению товара B. Смешивание групп без этого шага — распространённая и трудно заметная ошибка утечки данных.
df_multi = pd.DataFrame({
'product': ['A', 'A', 'A', 'B', 'B', 'B'],
'sales': [100, 120, 115, 200, 210, 195]
})
# WRONG: lag crosses product boundary
df_multi['lag_wrong'] = df_multi['sales'].shift(1)
# CORRECT: lag within each product
df_multi['lag_correct'] = df_multi.groupby('product')['sales'].shift(1)
print(df_multi)Интерпретация знаков pct_change
Положительное значение pct_change() означает, что текущее значение выше предыдущего; отрицательное — что оно ниже. Будьте внимательны к делению на ноль, если предыдущее значение равно нулю: результатом будет NaN или inf в зависимости от знака текущего значения. Используйте replace([float('inf'), float('-inf')], float('nan')), чтобы очистить бесконечные значения после вызова pct_change().
import numpy as np
s = pd.Series([0, 100, 50, 200])
chg = s.pct_change()
print(chg)
# 0 NaN <- no prior value
# 1 inf <- 0 -> 100 (division by zero)
# 2 -0.5 <- 100 -> 50 (-50%)
# 3 3.0 <- 50 -> 200 (+300%)
# Clean infinite values
chg_clean = chg.replace([float('inf'), float('-inf')], float('nan'))
print(chg_clean)Быстрая проверка
Проверьте, насколько хорошо Вы поняли сдвиги и лаговые признаки из этого урока.
Итоги урока
В этом уроке Вы узнали, что shift(n) создаёт лаговые признаки, сдвигая значения вниз на n позиций; diff(n) вычисляет абсолютное изменение между периодами; pct_change(n) вычисляет относительное процентное изменение; а при работе с несколькими группами необходимо использовать groupby().shift(), чтобы избежать утечки данных. Далее мы извлечём временные признаки с помощью аксессора .dt.
Изучай Python с ИИ-репетитором — бесплатно
Пиши и запускай код прямо в браузере, получай мгновенную помощь от ИИ-репетитора 24/7 и продолжи учиться на сайте или в приложении.
- Курсы
- 30
- Уроки
- 120
Часто задаваемые вопросы
Урок «Сдвиги и признаки запаздывания» бесплатный?
Да — полный текст урока «Сдвиги и признаки запаздывания» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Pandas & NumPy Academy, подпишись на CoddyKit PRO. Курс Pandas & NumPy Academy содержит 4 уроков всего.
Чему я научусь в уроке «Сдвиги и признаки запаздывания»?
Создавайте столбцы с запаздыванием и опережением с помощью shift(), вычисляйте изменение между периодами с помощью diff() и рассчитывайте процентное изменение. Ты практикуешь Pandas & NumPy Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Pandas & NumPy Academy?
Предыдущий опыт не требуется. Pandas & NumPy Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.
Сколько времени занимает урок «Сдвиги и признаки запаздывания»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Pandas & NumPy Academy?
Да. Каждый урок Pandas & NumPy Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- DatetimeIndex и диапазоны периодов
- Ресэмплинг временных рядов
- Сдвиги и признаки запаздывания
- Извлечение временных признаков