Вопрос или проблема
Меня очень смущает меньшая потеря, но более высокий RMSE:
Вот новая модель с лучшими показателями потерь на том же наборе данных и с большим числом предикторов:
Сложение 3 из 3
Эпоха 1/10
170362/170362 [==============================] - 640s 4ms/step - loss: 4.7891e-04
Эпоха 2/10
170362/170362 [==============================] - 636s 4ms/step - loss: 1.0931e-04
Эпоха 3/10
170362/170362 [==============================] - 639s 4ms/step - loss: 8.6029e-05
Эпоха 4/10
170362/170362 [==============================] - 641s 4ms/step - loss: 7.6854e-05
Эпоха 5/10
170362/170362 [==============================] - 637s 4ms/step - loss: 6.7049e-05
Эпоха 6/10
170362/170362 [==============================] - 637s 4ms/step - loss: 6.3263e-05
Эпоха 7/10
170362/170362 [==============================] - 638s 4ms/step - loss: 5.8497e-05
Эпоха 8/10
170362/170362 [==============================] - 639s 4ms/step - loss: 6.2477e-05
Эпоха 9/10
170362/170362 [==============================] - 638s 4ms/step - loss: 5.3870e-05
Эпоха 10/10
170362/170362 [==============================] - 639s 4ms/step - loss: 5.4414e-05
170362/170362 [==============================] - 273s 2ms/step
85181/85181 [==============================] - 138s 2ms/step
Средний показатель по обучению: 1732.52 RMSE
Средний показатель по тестированию: 1732.63 RMSE
Старая модель с худшими показателями потерь на том же наборе данных, но с меньшим числом предикторов:
Сложение 3 из 3
Эпоха 1/5
164325/164325 [==============================] - 423s 3ms/step - loss: 2.1169e-04
Эпоха 2/5
164325/164325 [==============================] - 419s 3ms/step - loss: 1.4752e-04
Эпоха 3/5
164325/164325 [==============================] - 421s 3ms/step - loss: 1.3906e-04
Эпоха 4/5
164325/164325 [==============================] - 421s 3ms/step - loss: 1.3506e-04
Эпоха 5/5
164325/164325 [==============================] - 421s 3ms/step - loss: 1.3155e-04
41082/41082 [==============================] - 46s 1ms/step
20541/20541 [==============================] - 23s 1ms/step
Средний показатель по обучению: 1655.46 RMSE
Средний показатель по тестированию: 1655.44 RMSE
Пятая эпоха старой модели имеет loss: 1.3155e-04
с RMSE:
Средний показатель по обучению: 1655.46 RMSE
Средний показатель по тестированию: 1655.44 RMSE
Моя новая модель с большими данными и более низкой потерей за эпоху: loss: 5.4414e-05
имеет более высокий RMSE:
Средний показатель по обучению: 1732.52 RMSE
Средний показатель по тестированию: 1732.63 RMSE
Как это может быть? Мой код кажется вполне простым:
scaler_price = MinMaxScaler(feature_range=(0, 1))
scaler_features = MinMaxScaler(feature_range=(0, 1))
scaled_price = scaler_price.fit_transform(stack[['target']])
# Я поместил все признаки сюда, чтобы я мог итеративно использовать подмножества и видеть, какие из них работают лучше
scaled_features = scaler_features.fit_transform(stack[[
# 128 признаков здесь, не включая цель
]])
scaled_data = np.concatenate([scaled_price, scaled_features], axis=1)
from keras.utils import Sequence
import numpy as np
import keras
from sklearn.model_selection import KFold
from keras.models import Sequential
from keras.layers import LSTM, Dropout, Dense
from keras.optimizers import Adam
import math
from sklearn.metrics import mean_squared_error
# определение пользовательского генератора данных
class TimeSeriesGenerator(Sequence):
def __init__(self, data, targets, length, batch_size):
self.data, self.targets = data, targets
self.length = length
self.batch_size = batch_size
def __len__(self):
return int(np.ceil(len(self.data) / float(self.batch_size)))
def __getitem__(self, idx):
batch_x = self.data[idx * self.batch_size:(idx + 1) * self.batch_size]
batch_y = self.targets[idx * self.batch_size:(idx + 1) * self.batch_size]
return np.array(batch_x), np.array(batch_y)
# первоначальная настройка
n_epochs = 10
n_batch_size = 8
look_back = 10
X, y = create_dataset(scaled_data, look_back)
k = 3
random_seed = 13
kf = KFold(n_splits=k, shuffle=True, random_state=random_seed)
train_scores = []
test_scores = []
for i, (train_index, test_index) in enumerate(kf.split(X)):
print(f"\nСложение {i + 1} из {kf.get_n_splits()}\n")
X_train, X_test = X[train_index], X[test_index]
y_train, y_test = y[train_index], y[test_index]
# создание генераторов данных
train_generator = TimeSeriesGenerator(X_train, y_train, look_back, n_batch_size)
test_generator = TimeSeriesGenerator(X_test, y_test, look_back, n_batch_size)
# определение модели
model = Sequential([
LSTM(250, input_shape=(X_train.shape[1], X_train.shape[2]), return_sequences=True),
Dropout(0.2),
LSTM(100),
Dense(1)
])
model.compile(optimizer=Adam(), loss="mean_squared_error")
# начало экспериментального кода
log_dir = "logs/fit/" + datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
tensorboard_callback = tf.keras.callbacks.TensorBoard(log_dir=log_dir, histogram_freq=1)
# Запустите TensorBoard через командную строку или в среде блокнота. Два интерфейса обычно одинаковые. В блокнотах используйте магию строки %tensorboard. В командной строке выполните ту же команду без "%".
# %tensorboard --logdir logs/fit
# конец экспериментального кода
# обучение модели с использованием генератора
model.fit(train_generator, epochs=n_epochs, verbose=1)
# предсказание и оценка
train_predict = model.predict(train_generator)
test_predict = model.predict(test_generator)
train_predict = scaler_price.inverse_transform(train_predict)
test_predict = scaler_price.inverse_transform(test_predict)
train_score = math.sqrt(mean_squared_error(y_train[:len(train_predict)], train_predict))
test_score = math.sqrt(mean_squared_error(y_test[:len(test_predict)], test_predict))
train_scores.append(train_score)
test_scores.append(test_score)
# расчет средних оценок
avg_train_score = np.mean(train_scores)
avg_test_score = np.mean(test_scores)
print(f'Средний показатель по обучению: {avg_train_score:.2f} RMSE')
print(f'Средний показатель по тестированию: {avg_test_score:.2f} RMSE')
В этом случае высокие значения RMSE указывают на большие ошибки, которые все еще происходят, даже несмотря на то, что ваше среднее значение MSE меньше. Помните, RMSE сильно штрафует за большие ошибки, так что в вашем случае частота ошибок меньше; однако сами ошибки более значительны.
Ответ или решение
Ситуация, когда у вас наблюдаются низкие значения потерь (loss), но высокие значения среднеквадратичной ошибки (RMSE), может быть несколько парадоксальной, но она объяснима с точки зрения статистики и метрик оценки модели. Давайте разберем этот вопрос подробнее.
Объяснение
-
Различие между Loss и RMSE:
- Потеря (Loss): Обычно, когда мы говорим о потерях в контексте LSTM, это значение функции потерь, например, среднеквадратичной ошибки (MSE). Это значение рассчитывается на всех предсказанных значениях модели. Низкие значения потерь указывают на то, что ваша модель хорошо предсказывает в среднем.
- RMSE: Это среднеквадратичная ошибка, которая дополнительно учитывает масштаб ошибок, накладывая больший штраф за более крупные ошибки. RMSE менее устойчив к выбросам, чем среднее значение потерь.
-
Влияние выбросов:
- Если ваша новая модель имеет более низкие потери, это может означать, что она лучше справляется с предсказаниями для большей части данных. Однако, если где-то в данных имеются выбросы (значения, существенно отличающиеся от остальных), модель может плохо работать именно с этими данными. Это может вести к высокому RMSE, поскольку RMSE выше "наказывает" на крупные ошибки.
-
Сложность модели:
- Ваша новая модель имеет больше предикторов и может быть более сложной, чем предыдущая. Это может привести к переобучению, когда модель слишком подстраивается под обучающие данные. Если модель начала выдавать точные предсказания для основной массы данных, это не означает, что она будет хорошо предсказывать для всех значений, особенно для тех, которые выходят за пределы статистической нормы.
-
Различие в масштабах данных:
- Если ваши данные были стандартизированы или нормализованы (как в вашем примере с
MinMaxScaler
), но вы не учли возможные различия в распределениях целевых переменных, это может привести к ситуации, когда модели прекрасно работают на нормально распределённых, но плохо на выбросах.
- Если ваши данные были стандартизированы или нормализованы (как в вашем примере с
Рекомендации
-
Изучение остатков: Постройте график остатков (разницы между предсказанными и фактическими значениями) для того, чтобы выявить паттерны, указывающие на наличие выбросов.
-
Подбор модели: Попробуйте упростить модель или изменить ее архитектуру, например, уменьшить количество LSTM-нейронов или добавить регуляризацию (Dropout).
-
Проверка на выбросы: Обратите внимание на ваши данные на наличие выбросов, которые могут сбивать с толку вашу модель. Обработка выбросов может помочь в в дальнейшем повысить качество предсказаний.
-
Использование других метрик: Рассмотрите возможность использования других метрик для оценки вашей модели, которые могут быть более устойчивыми к выбросам, например, MAE (средняя абсолютная ошибка).
В заключение, для корректного интерпретирования результатов вашей модели важно учитывать как значения потерь, так и RMSE. Высокое значение RMSE при низких потерях может указывать на наличие проблем с выбросами или переобучением.