Финансовая модель LSTM всегда предсказывает одно и то же значениеPython

Программы на Python
Ответить
Anonymous
 Финансовая модель LSTM всегда предсказывает одно и то же значение

Сообщение Anonymous »

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

Код: Выделить всё

def create_sequences(data, seq_length, feature_cols, target_col):
features = feature_cols.copy()
features.remove('ticker')
ticker_list = []
X = []
y = []

for ticker in data["ticker"].unique():
ticker_data = data[data["ticker"] == ticker].reset_index(drop=True)
ticker_data = ticker_data.drop('ticker', axis=1)
for i in range(seq_length, len(ticker_data)):
X.append(ticker_data.loc[i - seq_length: i - 1, features].values)
y.append(ticker_data.loc[i, target_col])
ticker_list.append(ticker)
return ticker_list, np.asarray(X), np.asarray(y)
Длина последовательности равна 5, потому что мне нужны первые 5 дней, чтобы спрогнозировать шестой, а цена закрытия является признаком как в векторе X признака, так и в векторе y этикетки. Объектами вектора x являются: ["день","месяц","год","день недели","тикер","ticker_emb","title_count","объем","закрыть"], особенностью вектора y является ["close"].
Затем я определил следующие функции для масштабирования и создания набора данных:

Код: Выделить всё

def define_scalers_per_ticker(dataframe_train):
price_column = "close"
scaler = {}

for ticker in dataframe_train["ticker"].unique():
ticker_data = dataframe_train[dataframe_train["ticker"] == ticker]

scaler[ticker] = {}

price_scaler = MinMaxScaler(feature_range = (0,1))
price_scaler.fit(ticker_data[[price_column]])
scaler[ticker][price_column] = price_scaler

volume_scaler = MinMaxScaler(feature_range = (0,1))
volume_scaler.fit(ticker_data[["volume"]])
scaler[ticker]["volume"] = volume_scaler

return scaler

def scale_ticker_data(scaler, dataframe):
scaled_dataframe = dataframe.copy()

numeric_columns = ["close", "volume"]
scaled_dataframe[numeric_columns] = scaled_dataframe[numeric_columns].astype("float32")

for ticker in dataframe["ticker"].unique():
ticker_mask = dataframe["ticker"] == ticker

for column in numeric_columns:
scaled_values = scaler[ticker][column].transform(
scaled_dataframe.loc[ticker_mask, [column]]
)
scaled_dataframe.loc[ticker_mask, [column]] = scaled_values

return scaled_dataframe

def scale_dataframe(train_dataframe: pd.DataFrame, test_dataframe: pd.DataFrame):
scaler = define_scalers_per_ticker(train_dataframe)

df_train_trs = scale_ticker_data(scaler, train_dataframe)
df_test_trs = scale_ticker_data(scaler, test_dataframe)

return scaler, df_train_trs, df_test_trs
Я определяю следующую модель набора данных и модель lstm:

Код: Выделить всё

class TemporalDataset(Dataset):
def __init__(self, tickers, sequence_data, labels):
self.data = sequence_data
self.tickers = tickers
self.labels = labels

def __len__(self):
return len(self.data)

def __getitem__(self, idx)->Dict:
ticker = self.tickers[idx]
data = torch.tensor(self.data[idx], dtype=torch.float32)
labels = torch.tensor(self.labels[idx], dtype=torch.float32)
sample = {'ticker': ticker, 'data': data, 'labels': labels}
return sample

class BaseLstmVar(nn.Module):
def __init__(self, input_size, hidden_size, num_lstm_layers, lstm_dropout,  dropout, output_size):
super(BaseLstmVar, self).__init__()
self.name = "BaseLSTMVar"
self.lstm =nn.LSTM(
input_size=input_size,
hidden_size=hidden_size,
num_layers=num_lstm_layers,
batch_first=True,
bidirectional=True,
dropout=lstm_dropout if num_lstm_layers >  1 else 0
)

self.fc1 = nn.Linear(2*hidden_size, 50)

self.dropout = nn.Dropout(dropout)
self.fc2 = nn.Linear(50, output_size)
self.leaky_relu = nn.LeakyReLU()

def forward(self, x):
lstm_out, (hn, cn) = self.lstm(x)
target = torch.mean(lstm_out, dim=1)

out = self.fc1(target)

out = self.leaky_relu(out)
out = self.dropout(out)

out = self.fc2(out)

return out
В конечном итоге цикл поезда был определен как:

Код: Выделить всё

ticker_list_train, x_train, y_train = create_sequences(
df_train_model, sequence_length, feature, 'close', True
)
ticker_list_test, x_test, y_test = create_sequences(
df_test_model, sequence_length, feature, 'close', True
)

train_dataset = TemporalDataset(
ticker_list_train, x_train, y_train
)
test_dataset = TemporalDataset(
ticker_list_test, x_test, y_test
)

batch_size = 32

train_dataloader = DataLoader(train_dataset, batch_size=batch_size, shuffle=False)
test_dataloader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)

net = BaseLstmVar(
input_dim, hidden_lstm_size, lstm_num_layers, lstm_drp, dropout_rate, output_size
)

print(net)

epochs = 2
learning_rate = 1e-3
criterion = nn.MSELoss()
optimizer = optim.AdamW(net.parameters(), lr=learning_rate)
device = detect_device()

train_logger = instantiate_logger(f"{model}_{net.name}_train_logger_pkl")

net = net.to(device)

# training
losses = []
for epoch in range(epochs):
net.train()
epoch_loss = 0

train_logger.info(
f"Starting epoch {epoch + 1}/{epochs}"
)

for idx_batch, batch in enumerate(train_dataloader):
optimizer.zero_grad()
batch_x, batch_y = batch['data'].to(device), batch['labels'].to(device)
outputs = net(batch_x)
loss = criterion(outputs, batch_y.reshape(-1, 1))
loss.backward()
optimizer.step()

loss_rnd = round(loss.item(), 4)
epoch_loss += loss_rnd
train_logger.info(
f"Batch [{idx_batch + 1}/{len(train_dataloader)}], \t Loss: {loss_rnd: .4f}"
)

avg_epoch = epoch_loss / len(train_dataloader)
losses.append(avg_epoch)
train_logger.info(
f"Avg epoch loss in {epoch + 1} epoch: {avg_epoch:.4f}"
)
Если я попрошу модель сделать прогноз для пакета, проблема в том, что у меня всегда будет один и тот же прогноз. Например, реальные значения — 25, 43, 52, но прогнозируемые значения всегда равны, например, 63.

Код: Выделить всё

batch = next(iter(test_dataloader))
tickers, data, labels = batch['ticker'], batch['data'].to(device), batch['labels'].to(device)

output_test = net(data).detach().cpu().numpy()
output_real = labels.cpu().numpy()

unsc_out_test = []
unsc_out_real = []
for idx, ticker in enumerate(tickers):
unsc_out_test.append(scaler[ticker]['close'].inverse_transform(output_test[idx].reshape(-1, 1)).item())
unsc_out_real.append(scaler[ticker]['close'].inverse_transform(output_real[idx].reshape(-1, 1)).item())
Где я делаю не так? Я не знаю, почему моя модель предсказывает неправильные значения. Я также пробовал менять номера эпох или функцию потерь с помощью HuberLoss, но результаты не меняются.


Подробнее здесь: https://stackoverflow.com/questions/791 ... same-value
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Python»