Dica: Este caso é apenas para fins de estudo e pesquisa e não constitui uma recomendação de investimento.
Os dados de preço do Bitcoin são baseados em sequências de tempo, portanto, as previsões de preço do Bitcoin são realizadas principalmente usando o modelo LSTM.
A memória de curto prazo (LSTM) é um modelo de aprendizagem profunda especialmente adaptado para dados de sequência de tempo (ou dados com ordem de tempo / espaço / estrutura, como filmes, frases, etc.) e é o modelo ideal para prever a direção do preço das criptomoedas.
Este artigo foi escrito principalmente para combinar dados através do LSTM para prever o preço futuro do Bitcoin.
import pandas as pd
import numpy as np
from sklearn.preprocessing import MinMaxScaler, LabelEncoder
from keras.models import Sequential
from keras.layers import LSTM, Dense, Dropout
from matplotlib import pyplot as plt
%matplotlib inline
Carregamento de dados
Leia os dados diários de negociação do BTC
data = pd.read_csv(filepath_or_buffer="btc_data_day")
Os dados disponíveis são de 1380 colunas: Data, Open, High, Low, Close, Volume (BTC), Volume (Currency) e Weighted Price. As colunas restantes são de tipo float64, exceto a coluna Date.
data.info()
Veja as 10 primeiras linhas.
data.head(10)
Visualização de dados
Usando o matplotlib, traçamos o preço ponderado para ver a distribuição e a tendência dos dados. No gráfico, encontramos uma parte de dados 0 e precisamos confirmar se há alguma anomalia nos dados abaixo.
plt.plot(data['Weighted Price'], label='Price')
plt.ylabel('Price')
plt.legend()
plt.show()
Processamento de dados anormais
Primeiro, vamos ver se o nosso dado contém dados de nanos, e podemos ver que o nosso dado não tem dados de nanos.
data.isnull().sum()
Date 0
Open 0
High 0
Low 0
Close 0
Volume (BTC) 0
Volume (Currency) 0
Weighted Price 0
dtype: int64
Então, se você olhar para baixo para o dado 0, você pode ver que o nosso dado tem um valor zero, e nós precisamos de processá-lo.
(data == 0).astype(int).any()
Date False
Open True
High True
Low True
Close True
Volume (BTC) True
Volume (Currency) True
Weighted Price True
dtype: bool
data['Weighted Price'].replace(0, np.nan, inplace=True)
data['Weighted Price'].fillna(method='ffill', inplace=True)
data['Open'].replace(0, np.nan, inplace=True)
data['Open'].fillna(method='ffill', inplace=True)
data['High'].replace(0, np.nan, inplace=True)
data['High'].fillna(method='ffill', inplace=True)
data['Low'].replace(0, np.nan, inplace=True)
data['Low'].fillna(method='ffill', inplace=True)
data['Close'].replace(0, np.nan, inplace=True)
data['Close'].fillna(method='ffill', inplace=True)
data['Volume (BTC)'].replace(0, np.nan, inplace=True)
data['Volume (BTC)'].fillna(method='ffill', inplace=True)
data['Volume (Currency)'].replace(0, np.nan, inplace=True)
data['Volume (Currency)'].fillna(method='ffill', inplace=True)
(data == 0).astype(int).any()
Date False
Open False
High False
Low False
Close False
Volume (BTC) False
Volume (Currency) False
Weighted Price False
dtype: bool
Agora, se olharmos para a distribuição dos dados e para a tendência, a curva já é muito contínua.
plt.plot(data['Weighted Price'], label='Price')
plt.ylabel('Price')
plt.legend()
plt.show()
Segmentação dos conjuntos de dados de treinamento e de teste
Unificar dados para 0 a 1
data_set = data.drop('Date', axis=1).values
data_set = data_set.astype('float32')
mms = MinMaxScaler(feature_range=(0, 1))
data_set = mms.fit_transform(data_set)
Divide os conjuntos de dados de testes e de treinamento em 2:8.
ratio = 0.8
train_size = int(len(data_set) * ratio)
test_size = len(data_set) - train_size
train, test = data_set[0:train_size,:], data_set[train_size:len(data_set),:]
Criar um conjunto de dados de treinamento e de teste, com um dia como janela para criar nosso conjunto de dados de treinamento e de teste.
def create_dataset(data):
window = 1
label_index = 6
x, y = [], []
for i in range(len(data) - window):
x.append(data[i:(i + window), :])
y.append(data[i + window, label_index])
return np.array(x), np.array(y)
train_x, train_y = create_dataset(train)
test_x, test_y = create_dataset(test)
Desta vez, usamos um modelo simples, que tem a seguinte estrutura: 1. LSTM2. Dense.
Aqui é necessário explicar o formato de entrada do LSTM. A dimensão de entrada do Input Shape é batch_size, time steps, features. Aqui, o valor de time steps é o intervalo de janela de tempo no momento da entrada de dados.
A memória de curto prazo (LSTM) é uma espécie de RNN especializada, principalmente para resolver problemas de desaparecimento de gradientes e explosão de gradientes durante o treinamento de séries longas.
A partir do gráfico de estrutura da rede do LSTM, pode-se ver que o LSTM é, na verdade, um modelo pequeno, que contém três funções de ativação sigmoide, duas funções de ativação tanh, três multiplicações e uma adição.
Estado celular
O estado da célula é o núcleo do LSTM, ele é a linha preta no topo do gráfico acima, e abaixo desta linha preta há algumas portas, que vamos descrever mais adiante. O estado da célula é atualizado com base nos resultados de cada porta.
A rede LSTM pode remover ou adicionar informações sobre o estado da célula através de uma estrutura chamada porta. A porta pode ter uma decisão seletiva sobre qual informação passar. A estrutura da porta é uma combinação de um sigmoide e uma operação de multiplicação de pontos.
A porta esquecida
O primeiro passo do LSTM é decidir qual informação o estado celular precisa descartar. Esta parte da operação é processada por uma unidade sigmoide chamada porta do esquecimento.
Podemos ver que a porta de esquecimento produz um vetor entre 0 e 1 ao olhar para as informações $h_{l-1}$ e $x_{t}$, onde o valor 0 a 1 indica o quanto da informação no estado celular $C_{t-1}$ é mantida ou descartada. 0 significa não mantida e 1 significa mantida.
A expressão matemática: $f_{t}=\sigma\left ((W_{f} \cdot\left[h_{t-1}, x_{t}\right]+b_{f}\right) $
A entrada
O próximo passo é decidir que novas informações devem ser adicionadas ao estado da célula, o que é feito através da entrada.
Vemos que as informações de $h_{l-1}$ e $x_{t}$ são novamente inseridas em um segmoide e na entrada tanh. Como o resultado do segmoide é um valor de 0-1, portanto, se o segmoide é 0, o resultado $C_{i}$ após a entrada não será adicionado ao estado atual da célula, se for 1, tudo será adicionado ao estado da célula, portanto, o papel do segmoide aqui é adicionar seletivamente o resultado do segmoide ao estado da célula.
A fórmula matemática é: $C_{t}=f_{t} * C_{t-1} + i_{t} * \tilde{C}_{t}$
Portão de saída
Após a atualização do estado da célula, é necessário determinar quais características de estado da célula são feitas com base nos sumos de $h_{l-1}$ e $x_{t}$, onde a entrada é feita através de uma camada sigmoide chamada porta de saída, e o estado da célula é feito através da camada tanh para obter um vetor de um valor entre -1 e 1, que é multiplicado pelas condições de decisão obtidas pela porta de saída e obtém a saída da unidade final do RNA.
def create_model():
model = Sequential()
model.add(LSTM(50, input_shape=(train_x.shape[1], train_x.shape[2])))
model.add(Dense(1))
model.compile(loss='mae', optimizer='adam')
model.summary()
return model
model = create_model()
history = model.fit(train_x, train_y, epochs=80, batch_size=64, validation_data=(test_x, test_y), verbose=1, shuffle=False)
plt.plot(history.history['loss'], label='train')
plt.plot(history.history['val_loss'], label='test')
plt.legend()
plt.show()
train_x, train_y = create_dataset(train)
test_x, test_y = create_dataset(test)
predict = model.predict(test_x)
plt.plot(predict, label='predict')
plt.plot(test_y, label='ground true')
plt.legend()
plt.show()
No momento, é muito difícil prever o movimento do preço do Bitcoin a longo prazo usando o aprendizado de máquina, e este artigo só pode ser usado como um caso de aprendizagem. O caso será lançado em uma imagem demo da nuvem de matrizes, para que os usuários interessados possam experimentar diretamente.