Почему линейная регрессия не так хорошо справляется с валидацией методом скользящего окна?

Вопрос или проблема

Я следовал этому вопросу1,вопросу2.


У меня есть следующая задача: у меня есть временные ряды данных. Обучение проводится на последовательных 3 днях для прогнозирования каждого 4-го дня. Данные каждого дня представлены одним файлом CSV размером 24×25. Каждая точка данных в каждом файле CSV является пикселом.

Теперь мне нужно сделать следующее: предсказать 4-й день, используя обучающие данные 1-го, 2-го, 3-го дней (три предыдущих последовательных дня), а затем вычислить MSE между предсказанными данными 4-го дня и оригинальными данными 4-го дня. Назовем это mse1.

Аналогично, мне нужно предсказать 5-й день, используя обучающие данные 2-го, 3-го, 4-го дней, а затем вычислить mse2 (MSE между предсказанными данными 5-го дня и оригинальными данными 5-го дня).

Мне нужно предсказать 6-й день, используя обучающие данные 3-го, 4-го, 5-го дней, а затем вычислить mse3 (MSE между предсказанными данными 6-го дня и оригинальными данными 6-го дня).

……….

И, наконец, я хочу предсказать 93-й день, используя обучающие данные 90-го, 91-го, 92-го дней, и вычислить mse90 (MSE между предсказанными данными 93-го дня и оригинальными данными 93-го дня).

Я хочу использовать в данном случае линейную регрессию, и у нас есть 90 MSE для этой модели.

import os
import pandas as pd
import numpy as np
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import MinMaxScaler
import matplotlib.pyplot as plt

# Пути
data_folder = r'C:\Users\alokj\OneDrive\Desktop\jupyter_proj\All_data'
output_folder = r'C:\Users\alokj\OneDrive\Desktop\jupyter_proj\90_days_merged'

# Убедиться, что папка для вывода существует
os.makedirs(output_folder, exist_ok=True)

# Перечислить все файлы CSV в папке
csv_files = [f for f in os.listdir(data_folder) if f.endswith('.csv')]

# Отсортировать файлы на основе числовой части, извлеченной из имени файла
csv_files = sorted(csv_files, key=lambda x: int(x.split('_Day')[1].split('_')[0]))

# Подготовка данных
data_list = [pd.read_csv(os.path.join(data_folder, file), header=None).values for file in csv_files]
data_array = np.array(data_list)  # Форма: (num_days, 24, 25)

# Развернуть данные для удобства работы в моделях регрессии
num_days, rows, cols = data_array.shape
data_flattened = data_array.reshape(num_days, -1)  # Форма: (num_days, 600)

# ---- Пошаговая проверка: итеративное прогнозирование с 4 по 93 день ----
# Для каждого прогноза используем:
#   - Обучающие данные: предыдущие 3 дня (развернутые)
#   - Целевые данные: текущий день (который модель обучается отображать из 3-дневного окна)
#   - Затем прогнозируем следующий день, используя сдвинутое окно (последние 3 дня смещены на один)
# Это гарантирует, что в момент прогнозирования используются только предыдущие данные.

mse_list = []
# Мы предполагаем, что наши данные содержат дни с 1 по 93 (индексы с 0 по 92) так, что:
#  - Для прогноза 4 дня: обучающее окно = дни 1-3 (индексы 0-2), целевое значение = день 4 (индекс 3),
#    затем прогнозируем 5 день, используя окно дней 2-4 (индексы 1-3).
#  - Для прогноза 93 дня: обучающее окно = дни 90-92 (индексы 89-91), целевое значение = день 93 (индекс 92),
#    затем прогнозируем 94 день, используя окно дней 91-93 (индексы 90-92).
# Скорректируйте диапазон цикла по мере необходимости; здесь мы запускаем цикл для i с 3 по 92 (i - индекс дня, используемого как целевое значение обучения)
# чтобы прогноз на (день i+1) был доступен, когда i+1 <= 92.
for i in range(3, 93):  # i от 3 до num_days-2; прогноз будет для дня i+1.
    # Обучение: используйте предыдущие 3 дня, чтобы обучиться отображению на текущий день.
    X_train_i = data_flattened[i-3:i].flatten().reshape(1, -1)
    y_train_i = data_flattened[i].flatten().reshape(1, -1)

    lr_model_iter = LinearRegression()
    lr_model_iter.fit(X_train_i, y_train_i)

    # Прогноз: используйте сдвинутое окно (дни i-2, i-1, i) для прогноза на следующий день (день i+1)
    X_test_i = data_flattened[i-2:i+1].flatten().reshape(1, -1)
    y_pred_i = lr_model_iter.predict(X_test_i).flatten()

    # Истинное значение для дня i+1
    y_actual = data_flattened[i+1].flatten()
    mse_i = np.mean((y_pred_i - y_actual) ** 2)
    mse_list.append(mse_i)

# Построить график пошагового MSE (прогнозы для дней с 4 по num_days)
# Поскольку i в цикле идет с 3 по num_days-2, прогнозы соответствуют дням с 4 по num_days-1.
days_val = [f'Day {i+1}' for i in range(90)]
plt.figure(figsize=(12, 6))
plt.plot(days_val, mse_list, label="Пошаговое MSE для линейной регрессии", marker="o")
plt.xticks(ticks=range(0, len(days_val), 2), labels=[f'Day {i+1}' for i in range(0, len(days_val), 2)], rotation=45, ha="right")
plt.xlabel('Прогнозируемый день')
plt.ylabel('MSE')
plt.title('Пошаговая проверка MSE для линейной регрессии')
plt.legend()
plt.grid(True)
plt.savefig(os.path.join(output_folder, 'walk_forward_mse_linear.png'))
plt.show()

Мой результат:
enter image description here

Мы знаем, что модели линейной регрессии часто не очень хорошо работают с данными временных рядов, потому что обычно нарушается предположение о независимости и идентичности распределений данных.

На самом деле, я реализовал свой код на основе предложений @RobertLong’s ответ1,ответ2 из вышеупомянутых вопросов.

Хотя я получаю ожидаемый результат, может кто-нибудь проверить мою модель регрессии внутри кода (если я сделал какие-либо ошибки или баги, о которых я могу не знать)?

Моя папка с данными за все 93 дня ссылка, которую я использовал для кода.

Ответ или решение

Линейная регрессия часто считается базовым методом для анализа временных рядов, и ее ограниченная производительность в контексте валидации скользящим окном вполне объяснима. В данном случае вы сталкиваетесь с задачей прогнозирования значений пикселей временных рядов, представляющих собой данные за определенные дни, с использованием линейной регрессии. Интересно рассмотреть, почему линейная регрессия может не давать желаемых результатов в этом контексте.

Теория

Линейная регрессия основана на предположении о линейной зависимости между независимой переменной (или переменными) и зависимой переменной. В классическом случае это предполагает наличие независимой и одинаково распределенной (oid) структуры данных, что редко сочетается с природой временных рядов.

  1. Зависимость от времени: Временные ряды, как правило, не являются независимыми; каждое наблюдение зависит от предыдущих. В вашем подходе используется метод скользящего окна из трех дней для прогнозирования следующего, однако зависимость между днями может иметь нелинейный характер или учитывать дальние зависимости, которые базовая линейная регрессия не может охватить.

  2. Сезонность и тренды: В данных временного ряда часто присутствуют тренды и сезонные колебания, которые линейная регрессия может неправильно моделировать. Без адекватной обработки таких компонентов модель может предоставить смещенные или нестабильные прогнозы.

  3. Высокая размерность данных: Вы работаете с данными пикселей размером 24×25, что приводит к высокой размерности задачи при обобщении во временном измерении. Если зависимости между пикселями сложны, простая линейная модель может оказаться недостаточной для правильного захвата этих зависимостей.

Пример

Применим линейную регрессию для прогноза четвертого дня по предыдущим трем дням (как в вашем коде). Данные пикселей для каждого дня представлены матрицей 24×25 пикселей, но прогноза требует трансформации этих данных в одномерный массив, чтобы соответствовать требованиям формата данных для линейной регрессии:

X_train_i = data_flattened[i-3:i].flatten().reshape(1, -1)
y_train_i = data_flattened[i].flatten().reshape(1, -1)

В данном преобразовании происходит потеря пространственных зависимостей, характерных для изображений, которые могут существенно повлиять на точность прогноза. Линейная регрессия применяет те же ограничения на все параметры без учета геометрии данных.

Применение

Учитывая вышеупомянутые аспекты, можно предложить несколько рекомендаций для улучшения производительности прогноза:

  1. Преобразования данных: Прежде чем применить линейную регрессию, выполните предварительную обработку данных – выявите и моделируйте сезонность и тренды. Например, можно вычесть тренд из данных или использовать скользящее окно более длительного временного отрезка.

  2. Продвинутые модели: Рассмотрите возможность использования более сложных моделей, таких как ARIMA, LSTM или другие нейронные сети, которые могут эффективно справляться с временной зависимостью и улавливать нелинейные зависимости.

  3. Добавление других признаков: Учитывайте возможность создания и добавления новых признаков, которые могут помочь модели захватить тонкие зависимости и упростить задачу прогнозирования.

  4. Кросс-валидация: Используйте скользящее окно для кросс-валидации (например, Rolling Time Series Split), чтобы наилучшим образом оценить производительность модели на данных временного ряда.

Таким образом, важно осознать ограничения линейной регрессии в применении к временным рядам и рассмотреть альтернативные подходы и методы преобразования данных, чтобы максимально использовать доступные данные. Способность гибко адаптироваться к особенностям данных через адекватную предварительную обработку и применение продвинутых моделей часто является ключом к успешному прогнозированию и анализу временных рядов.

Оцените материал
Добавить комментарий

Капча загружается...