Анализ временных рядов в Pandas

Анализ временных рядов — важная часть анализа данных. Pandas предоставляет богатый функционал для обработки и анализа данных временных рядов, включая ресемплинг, скользящие вычисления, скользящие средние и т. д.


Базовые операции с временными рядами

Создание временных рядов

Пример

import pandas as pd
import numpy as np

# Создание данных временного ряда
np.random.seed(42)
dates = pd.date_range("2024-01-01", periods=100, freq="D")

ts = pd.Series(
    np.random.randn(100).cumsum() + 100,
    index=dates
)

print("Данные временного ряда (первые 10 элементов):")
print(ts.head(10))
print()

# Просмотр информации
print(f"Тип индекса: {type(ts.index)}")
print(f"Время начала: {ts.index.min()}")
print(f"Время окончания: {ts.index.max()}")
print(f"Промежуток времени: {ts.index.max() - ts.index.min()}")

Установка даты в качестве индекса

Пример

import pandas as pd
import numpy as np

# Создать DataFrame и установить индекс по дате
df = pd.DataFrame({
    "Date": pd.date_range("2024-01-01", periods=30, freq="D"),
    "Sales": np.random.randint(100, 500, 30),
    "Visitors": np.random.randint(50, 200, 30)
})

print("До установки:")
print(df.head())
print()

# Установить дату в качестве индекса
df = df.set_index("Date")
print("После установки:")
print(df.head())
print()

# Использовать loc для запроса по дате
print("Запрос с 2024-01-05 по 2024-01-10:")
print(df.loc["2024-01-05":"2024-01-10"])

Ресемплинг

Ресемплинг — это процесс преобразования данных временных рядов из одной частоты в другую, включая апсэмплинг (увеличение количества точек данных) и даунсэмплинг (уменьшение количества точек данных).

Понижающая дискретизация

Пример

import pandas as pd
import numpy as np

# Создание данных дневного уровня
np.random.seed(42)
dates = pd.date_range("2024-01-01", periods=90, freq="D")
ts = pd.Series(np.random.randint(100, 500, 90), index=dates)

print("Данные дневного уровня (первые 10 элементов):")
print(ts.head(10))
print()

# Передискретизация по месяцам (сумма)
monthly = ts.resample("M").sum()
print("Сумма по месяцам:")
print(monthly)
print()

# Передискретизация по месяцам (среднее)
monthly_mean = ts.resample("M").mean()
print("Среднее по месяцам:")
print(monthly_mean)

Повышающая дискретизация

Пример

import pandas as pd

# Создание низкочастотных данных
dates = pd.date_range("2024-01-01", periods=3, freq="M")
ts = pd.Series([100, 200, 150], index=dates)

print("Данные месячного уровня:")
print(ts)
print()

# Повышение частоты до дневного уровня (требуется метод заполнения)
ts_daily = ts.resample("D").ffill()
print("Повышена частота до дневного уровня (первые 10 элементов):")
print(ts_daily.head(10))

Распространённые методы ресемплинга

Метод Описание
sum() Sum
mean() Среднее
max() / min() Максимальное/минимальное значение
first() / last() Первое/последнее значение
count() Количество непустых значений
ohlc() Открытие, максимум, минимум, закрытие

Скользящие вычисления

Скользящее вычисление — это вычисление по скользящему окну на данных временных рядов, обычно используется для вычисления скользящих средних, скользящих стандартных отклонений и т. д.

Скользящее среднее

Пример

import pandas as pd
import numpy as np

# Создание данных
np.random.seed(42)
dates = pd.date_range("2024-01-01", periods=30, freq="D")
ts = pd.Series(np.random.randint(100, 200, 30), index=dates)

# Вычислить 7-дневное скользящее среднее
rolling_mean = ts.rolling(window=7).mean()
print("7-дневное скользящее среднее (первые 10 элементов):")
print(rolling_mean.head(10))
print()

# Вычислить 7-дневное скользящее стандартное отклонение
rolling_std = ts.rolling(window=7).std()
print("7-дневное скользящее стандартное отклонение:")
print(rolling_std.head(10))

Применение пользовательской функции в скользящем окне

Пример

import pandas as pd
import numpy as np

ts = pd.Series(range(1, 11))

print("Исходные данные:")
print(ts)
print()

# Скользящая сумма
print("Скользящая сумма 3:")
print(ts.rolling(3).sum())
print()

# Скользящий максимум
print("Скользящий максимум 3:")
print(ts.rolling(3).max())
print()

# Использовать apply
print("Пользовательская функция скользящего окна 3 (диапазон):")
print(ts.rolling(3).apply(lambda x: x.max() - x.min()))

Визуализация данных временных рядов

Пример

import pandas as pd
import numpy as np

# Создание тестовых данных
np.random.seed(42)
dates = pd.date_range("2024-01-01", periods=100, freq="D")
ts = pd.Series(
    np.random.randn(100).cumsum() + 100,
    index=dates
)

# Вычислить скользящее среднее
ma_7 = ts.rolling(7).mean()
ma_30 = ts.rolling(30).mean()

# Отображение данных
print("Временной ряд + скользящее среднее:")
print(f"Исходные данные (первые 5 элементов): {ts.head().tolist()}")
print(f"7-дневное скользящее среднее (первые 10 элементов): {ma_7.dropna().head().tolist()}")
print(f"30-дневное скользящее среднее (последние 5 элементов): {ma_30.dropna().tail().tolist()}")

Извлечение признаков временного ряда

Пример

import pandas as pd

# Создание временного ряда
ts = pd.Series(
    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
    index=pd.date_range("2024-01-01", periods=10, freq="D")
)

# Разность
diff = ts.diff()
print("Разность первого порядка:")
print(diff)
print()

# Процентное изменение
pct = ts.pct_change()
print("Процентное изменение:")
print(pct)
print()

# Сдвиг
shifted = ts.shift(1)
print("Сдвиг назад на 1:")
print(shifted)

Практическое занятие: Анализ данных об акциях

Пример

import pandas as pd
import numpy as np

# Имитация данных об акциях
np.random.seed(42)
n_days = 60

df = pd.DataFrame({
    "Дата": pd.date_range("2024-01-01", periods=n_days, freq="D"),
    "Цена открытия": 100 + np.random.randn(n_days).cumsum(),
    "Цена закрытия": 100 + np.random.randn(n_days).cumsum(),
    "Объём": np.random.randint(1000000, 10000000, n_days)
})
df = df.set_index("Date")

# Рассчитать дневную доходность
df["Return"] = df["Close price"].pct_change()

# Рассчитать волатильность (7-дневное скользящее стандартное отклонение)
df["Volatility"] = df["Return"].rolling(7).std() * np.sqrt(252)  # Привести к годовому значению

# Рассчитать линию скользящей средней
df["MA5"] = df["Close price"].rolling(5).mean()
df["MA20"] = df["Close price"].rolling(20).mean()

# Сгенерировать торговые сигналы (золотой крест / крест смерти)
df["Signal"] = 0
df.loc[df["MA5"] > df["MA20"], "Signal"] = 1
df.loc[df["MA5"] < df["MA20"], "Signal"] = -1

print("Результаты анализа биржевых данных:")
print(df.tail(10))

Распространённые проблемы

1. Даты не являются непрерывными

Некоторые временные ряды не имеют данных за каждый день (праздники и т. д.), нужно использоватьasfreqилиreindexдля обработки.

2. Проблемы с часовыми поясами

При обработке данных с разными часовыми поясами используйтеtz_localizeиtz_convertдля установки и преобразования часового пояса.

3. Влияние пропущенных значений

Скользящие расчёты по умолчанию пропускают пропущенные значения, но это может повлиять на непрерывность результатов.

Анализ временных рядов — это фундаментальный навык в финансах, метеорологии, IoT и других областях. Pandas предоставляет полный набор инструментов для обработки таких данных.

Другие расширения