|
|
|
|
移动端
创建专栏

手把手教你9步完成Python加密货币的价格预测

预测加密货币价格其实很简单,用Python+Keras,再来一个循环神经网络(确切说是双向LSTM),只需要9步就可以了!比特币以太坊价格预测都不在话下。

作者:文摘菌|2018-05-07 15:55

【新品产上线啦】51CTO播客,随时随地,碎片化学习

作 者 | Siraj Raval 

翻 译 | 糖竹子、狗小白、邓子稷

预测加密货币价格其实很简单,用Python+Keras,再来一个循环神经网络(确切说是双向LSTM),只需要9步就可以了!比特币以太坊价格预测都不在话下。

这9个步骤是:

  1. 数据处理
  2. 建模
  3. 训练模型
  4. 测试模型
  5. 分析价格变化
  6. 分析价格百分比变化
  7. 比较预测值和实际数据
  8. 计算模型评估指标
  9. 结合在一起:可视化

数据处理

导入Keras、Scikit learn的metrics、numpy、pandas、matplotlib这些我们需要的库。

  1. ## Keras for deep learning 
  2. from keras.layers.core import Dense, Activation, Dropout 
  3. from keras.layers.recurrent import LSTM 
  4. from keras.layers import Bidirectional 
  5. from keras.models import Sequential 
  6.  
  7. ## Scikit learn for mapping metrics 
  8. from sklearn.metrics import mean_squared_error 
  9.  
  10. #for logging 
  11. import time 
  12.  
  13. ##matrix math 
  14. import numpy as np 
  15. import math 
  16.  
  17. ##plotting 
  18. import matplotlib.pyplot as plt 
  19.  
  20. ##data processing 
  21. import pandas as pd 

首先,要对数据进行归一化处理。

  1. def load_data(filename, sequence_length): 
  2.     """ 
  3.     Loads the bitcoin data 
  4.      
  5.     Arguments: 
  6.     filename -- A string that represents where the .csv file can be located 
  7.     sequence_length -- An integer of how many days should be looked at in a row 
  8.      
  9.     Returns: 
  10.     X_train -- A tensor of shape (2400, 49, 35) that will be inputed into the model to train it 
  11.     Y_train -- A tensor of shape (2400,) that will be inputed into the model to train it 
  12.     X_test -- A tensor of shape (267, 49, 35) that will be used to test the model's proficiency 
  13.     Y_test -- A tensor of shape (267,) that will be used to check the model's predictions 
  14.     Y_daybefore -- A tensor of shape (267,) that represents the price of bitcoin the day before each Y_test value 
  15.     unnormalized_bases -- A tensor of shape (267,) that will be used to get the true prices from the normalized ones 
  16.     window_size -- An integer that represents how many days of X values the model can look at at once 
  17.     """ 
  18.     #Read the data file 
  19.     raw_data = pd.read_csv(filename, dtype = float).values 
  20.      
  21.     #Change all zeros to the number before the zero occurs 
  22.     for x in range(0, raw_data.shape[0]): 
  23.         for y in range(0, raw_data.shape[1]): 
  24.             if(raw_data[x][y] == 0): 
  25.                 raw_data[x][y] = raw_data[x-1][y] 
  26.      
  27.     #Convert the file to a list 
  28.     data = raw_data.tolist() 
  29.      
  30.     #Convert the data to a 3D array (a x b x c)  
  31.     #Where a is the number of days, b is the window size, and c is the number of features in the data file 
  32.     result = [] 
  33.     for index in range(len(data) - sequence_length): 
  34.         result.append(data[index: index + sequence_length]) 
  35.      
  36.     #Normalizing data by going through each window 
  37.     #Every value in the window is divided by the first value in the window, and then 1 is subtracted 
  38.     d0 = np.array(result) 
  39.     dr = np.zeros_like(d0) 
  40.     dr[:,1:,:] = d0[:,1:,:] / d0[:,0:1,:] - 1 
  41.      
  42.     #Keeping the unnormalized prices for Y_test 
  43.     #Useful when graphing bitcoin price over time later 
  44.     start = 2400 
  45.     end = int(dr.shape[0] + 1) 
  46.     unnormalized_bases = d0[start:end,0:1,20] 
  47.      
  48.     #Splitting data set into training (First 90% of data points) and testing data (last 10% of data points) 
  49.     split_line = round(0.9 * dr.shape[0]) 
  50.     training_data = dr[:int(split_line), :] 
  51.      
  52.     #Shuffle the data 
  53.     np.random.shuffle(training_data) 
  54.      
  55.     #Training Data 
  56.     X_train = training_data[:, :-1] 
  57.     Y_train = training_data[:, -1] 
  58.     Y_trainY_train = Y_train[:, 20] 
  59.      
  60.     #Testing data 
  61.     X_test = dr[int(split_line):, :-1] 
  62.     Y_test = dr[int(split_line):, 49, :] 
  63.     Y_testY_test = Y_test[:, 20] 
  64.  
  65.     #Get the day before Y_test's price 
  66.     Y_daybefore = dr[int(split_line):, 48, :] 
  67.     Y_daybeforeY_daybefore = Y_daybefore[:, 20] 
  68.      
  69.     #Get window size and sequence length 
  70.     sequence_lengthsequence_length = sequence_length 
  71.     window_size = sequence_length - 1 #because the last value is reserved as the y value 
  72.      
  73.     return X_train, Y_train, X_test, Y_test, Y_daybefore, unnormalized_bases, window_size 

建模

我们用到的是一个3层RNN,dropout率20%。

双向RNN基于这样的想法:时间t的输出不仅依赖于序列中的前一个元素,而且还可以取决于未来的元素。比如,要预测一个序列中缺失的单词,需要查看左侧和右侧的上下文。双向RNN是两个堆叠在一起的RNN,根据两个RNN的隐藏状态计算输出。

举个例子,这句话里缺失的单词gym要查看上下文才能知道:

I go to the ( ) everyday to get fit.

  1. def initialize_model(window_size, dropout_value, activation_function, loss_function, optimizer): 
  2.     """ 
  3.     Initializes and creates the model to be used 
  4.      
  5.     Arguments: 
  6.     window_size -- An integer that represents how many days of X_values the model can look at at once 
  7.     dropout_value -- A decimal representing how much dropout should be incorporated at each level, in this case 0.2 
  8.     activation_function -- A string to define the activation_function, in this case it is linear 
  9.     loss_function -- A string to define the loss function to be used, in the case it is mean squared error 
  10.     optimizer -- A string to define the optimizer to be used, in the case it is adam 
  11.      
  12.     Returns: 
  13.     model -- A 3 layer RNN with 100*dropout_value dropout in each layer that uses activation_function as its activation 
  14.              function, loss_function as its loss function, and optimizer as its optimizer 
  15.     """ 
  16.     #Create a Sequential model using Keras 
  17.     model = Sequential() 
  18.  
  19.     #First recurrent layer with dropout 
  20.     model.add(Bidirectional(LSTM(window_size, return_sequences=True), input_shape=(window_size, X_train.shape[-1]),)) 
  21.     model.add(Dropout(dropout_value)) 
  22.  
  23.     #Second recurrent layer with dropout 
  24.     model.add(Bidirectional(LSTM((window_size*2), return_sequences=True))) 
  25.     model.add(Dropout(dropout_value)) 
  26.  
  27.     #Third recurrent layer 
  28.     model.add(Bidirectional(LSTM(window_size, return_sequences=False))) 
  29.  
  30.     #Output layer (returns the predicted value) 
  31.     model.add(Dense(units=1)) 
  32.      
  33.     #Set activation function 
  34.     model.add(Activation(activation_function)) 
  35.  
  36.     #Set loss function and optimizer 
  37.     model.compile(loss=loss_functionoptimizeroptimizer=optimizer) 
  38.      
  39.     return model 

训练模型

这里取batch size = 1024,epoch times = 100。我们需要最小化均方误差MSE。

  1. def fit_model(model, X_train, Y_train, batch_num, num_epoch, val_split): 
  2.     """ 
  3.     Fits the model to the training data 
  4.      
  5.     Arguments: 
  6.     model -- The previously initalized 3 layer Recurrent Neural Network 
  7.     X_train -- A tensor of shape (2400, 49, 35) that represents the x values of the training data 
  8.     Y_train -- A tensor of shape (2400,) that represents the y values of the training data 
  9.     batch_num -- An integer representing the batch size to be used, in this case 1024 
  10.     num_epoch -- An integer defining the number of epochs to be run, in this case 100 
  11.     val_split -- A decimal representing the proportion of training data to be used as validation data 
  12.      
  13.     Returns: 
  14.     model -- The 3 layer Recurrent Neural Network that has been fitted to the training data 
  15.     training_time -- An integer representing the amount of time (in seconds) that the model was training 
  16.     """ 
  17.     #Record the time the model starts training 
  18.     start = time.time() 
  19.  
  20.     #Train the model on X_train and Y_train 
  21.     model.fit(X_train, Y_train, batch_sizebatch_numnb_epoch=num_epochvalidation_splitval_split
  22.  
  23.     #Get the time it took to train the model (in seconds) 
  24.     training_time = int(math.floor(time.time() - start)) 
  25.     return model, training_time 

测试模型

  1. def test_model(model, X_test, Y_test, unnormalized_bases): 
  2.     """ 
  3.     Test the model on the testing data 
  4.      
  5.     Arguments: 
  6.     model -- The previously fitted 3 layer Recurrent Neural Network 
  7.     X_test -- A tensor of shape (267, 49, 35) that represents the x values of the testing data 
  8.     Y_test -- A tensor of shape (267,) that represents the y values of the testing data 
  9.     unnormalized_bases -- A tensor of shape (267,) that can be used to get unnormalized data points 
  10.      
  11.     Returns: 
  12.     y_predict -- A tensor of shape (267,) that represnts the normalized values that the model predicts based on X_test 
  13.     real_y_test -- A tensor of shape (267,) that represents the actual prices of bitcoin throughout the testing period 
  14.     real_y_predict -- A tensor of shape (267,) that represents the model's predicted prices of bitcoin 
  15.     fig -- A branch of the graph of the real predicted prices of bitcoin versus the real prices of bitcoin 
  16.     """ 
  17.     #Test the model on X_Test 
  18.     y_predict = model.predict(X_test) 
  19.  
  20.     #Create empty 2D arrays to store unnormalized values 
  21.     real_y_test = np.zeros_like(Y_test) 
  22.     real_y_predict = np.zeros_like(y_predict) 
  23.  
  24.     #Fill the 2D arrays with the real value and the predicted value by reversing the normalization process 
  25.     for i in range(Y_test.shape[0]): 
  26.         y = Y_test[i] 
  27.         predict = y_predict[i] 
  28.         real_y_test[i] = (y+1)*unnormalized_bases[i] 
  29.         real_y_predict[i] = (predict+1)*unnormalized_bases[i] 
  30.  
  31.     #Plot of the predicted prices versus the real prices 
  32.     fig = plt.figure(figsize=(10,5)) 
  33.     ax = fig.add_subplot(111) 
  34.     ax.set_title("Bitcoin Price Over Time") 
  35.     plt.plot(real_y_predict, color = 'green'label = 'Predicted Price'
  36.     plt.plot(real_y_test, color = 'red'label = 'Real Price'
  37.     ax.set_ylabel("Price (USD)") 
  38.     ax.set_xlabel("Time (Days)") 
  39.     ax.legend() 
  40.      
  41.     return y_predict, real_y_test, real_y_predict, fig 

分析价格变化

  1. def price_change(Y_daybefore, Y_test, y_predict): 
  2.     """ 
  3.     Calculate the percent change between each value and the day before 
  4.      
  5.     Arguments: 
  6.     Y_daybefore -- A tensor of shape (267,) that represents the prices of each day before each price in Y_test 
  7.     Y_test -- A tensor of shape (267,) that represents the normalized y values of the testing data 
  8.     y_predict -- A tensor of shape (267,) that represents the normalized y values of the model's predictions 
  9.      
  10.     Returns: 
  11.     Y_daybefore -- A tensor of shape (267, 1) that represents the prices of each day before each price in Y_test 
  12.     Y_test -- A tensor of shape (267, 1) that represents the normalized y values of the testing data 
  13.     delta_predict -- A tensor of shape (267, 1) that represents the difference between predicted and day before values 
  14.     delta_real -- A tensor of shape (267, 1) that represents the difference between real and day before values 
  15.     fig -- A plot representing percent change in bitcoin price per day, 
  16.     """ 
  17.     #Reshaping Y_daybefore and Y_test 
  18.     Y_daybefore = np.reshape(Y_daybefore, (-1, 1)) 
  19.     Y_test = np.reshape(Y_test, (-1, 1)) 
  20.  
  21.     #The difference between each predicted value and the value from the day before 
  22.     delta_predict = (y_predict - Y_daybefore) / (1+Y_daybefore) 
  23.  
  24.     #The difference between each true value and the value from the day before 
  25.     delta_real = (Y_test - Y_daybefore) / (1+Y_daybefore) 
  26.  
  27.     #Plotting the predicted percent change versus the real percent change 
  28.     fig = plt.figure(figsize=(10, 6)) 
  29.     ax = fig.add_subplot(111) 
  30.     ax.set_title("Percent Change in Bitcoin Price Per Day") 
  31.     plt.plot(delta_predict, color='green'label = 'Predicted Percent Change'
  32.     plt.plot(delta_real, color='red'label = 'Real Percent Change'
  33.     plt.ylabel("Percent Change") 
  34.     plt.xlabel("Time (Days)") 
  35.     ax.legend() 
  36.     plt.show() 
  37.      
  38.     return Y_daybefore, Y_test, delta_predict, delta_real, fig 

分析价格百分比变化

  1. def binary_price(delta_predict, delta_real): 
  2.     """ 
  3.     Converts percent change to a binary 1 or 0, where 1 is an increase and 0 is a decrease/no change 
  4.      
  5.     Arguments: 
  6.     delta_predict -- A tensor of shape (267, 1) that represents the predicted percent change in price 
  7.     delta_real -- A tensor of shape (267, 1) that represents the real percent change in price 
  8.      
  9.     Returns: 
  10.     delta_predict_1_0 -- A tensor of shape (267, 1) that represents the binary version of delta_predict 
  11.     delta_real_1_0 -- A tensor of shape (267, 1) that represents the binary version of delta_real 
  12.     """ 
  13.     #Empty arrays where a 1 represents an increase in price and a 0 represents a decrease in price 
  14.     delta_predict_1_0 = np.empty(delta_predict.shape) 
  15.     delta_real_1_0 = np.empty(delta_real.shape) 
  16.  
  17.     #If the change in price is greater than zero, store it as a 1 
  18.     #If the change in price is less than zero, store it as a 0 
  19.     for i in range(delta_predict.shape[0]): 
  20.         if delta_predict[i][0] > 0: 
  21.             delta_predict_1_0[i][0] = 1 
  22.         else: 
  23.             delta_predict_1_0[i][0] = 0 
  24.     for i in range(delta_real.shape[0]): 
  25.         if delta_real[i][0] > 0: 
  26.             delta_real_1_0[i][0] = 1 
  27.         else: 
  28.             delta_real_1_0[i][0] = 0     
  29.  
  30.     return delta_predict_1_0, delta_real_1_0 

比较预测值和实际数据

  1. def find_positives_negatives(delta_predict_1_0, delta_real_1_0): 
  2.     """ 
  3.     Finding the number of false positives, false negatives, true positives, true negatives 
  4.      
  5.     Arguments:  
  6.     delta_predict_1_0 -- A tensor of shape (267, 1) that represents the binary version of delta_predict 
  7.     delta_real_1_0 -- A tensor of shape (267, 1) that represents the binary version of delta_real 
  8.      
  9.     Returns: 
  10.     true_pos -- An integer that represents the number of true positives achieved by the model 
  11.     false_pos -- An integer that represents the number of false positives achieved by the model 
  12.     true_neg -- An integer that represents the number of true negatives achieved by the model 
  13.     false_neg -- An integer that represents the number of false negatives achieved by the model 
  14.     """ 
  15.     #Finding the number of false positive/negatives and true positives/negatives 
  16.     true_pos = 0 
  17.     false_pos = 0 
  18.     true_neg = 0 
  19.     false_neg = 0 
  20.     for i in range(delta_real_1_0.shape[0]): 
  21.         real = delta_real_1_0[i][0] 
  22.         predicted = delta_predict_1_0[i][0] 
  23.         if real == 1: 
  24.             if predicted == 1: 
  25.                 true_pos += 1 
  26.             else: 
  27.                 false_neg += 1 
  28.         elif real == 0: 
  29.             if predicted == 0: 
  30.                 true_neg += 1 
  31.             else: 
  32.                 false_pos += 1 
  33.     return true_pos, false_pos, true_neg, false_neg 

计算模型评估指标

  1. def calculate_statistics(true_pos, false_pos, true_neg, false_neg, y_predict, Y_test): 
  2.    """ 
  3.    Calculate various statistics to assess performance 
  4.     
  5.    Arguments: 
  6.    true_pos -- An integer that represents the number of true positives achieved by the model 
  7.    false_pos -- An integer that represents the number of false positives achieved by the model 
  8.    true_neg -- An integer that represents the number of true negatives achieved by the model 
  9.    false_neg -- An integer that represents the number of false negatives achieved by the model 
  10.    Y_test -- A tensor of shape (267, 1) that represents the normalized y values of the testing data 
  11.    y_predict -- A tensor of shape (267, 1) that represents the normalized y values of the model's predictions 
  12.     
  13.    Returns: 
  14.    precision -- How often the model gets a true positive compared to how often it returns a positive 
  15.    recall -- How often the model gets a true positive compared to how often is hould have gotten a positive 
  16.    F1 -- The weighted average of recall and precision 
  17.    Mean Squared Error -- The average of the squares of the differences between predicted and real values 
  18.    """ 
  19.    precision = float(true_pos) / (true_pos + false_pos) 
  20.    recall = float(true_pos) / (true_pos + false_neg) 
  21.    F1 = float(2 * precision * recall) / (precision + recall) 
  22.    #Get Mean Squared Error 
  23.    MSE = mean_squared_error(y_predict.flatten(), Y_test.flatten()) 
  24.  
  25.    return precision, recall, F1, MSE 

结合在一起:可视化

终于可以看看我们的成果啦!

首先是预测价格vs实际价格:

  1. y_predict, real_y_test, real_y_predict, fig1 = test_model(model, X_test, Y_test, unnormalized_bases) 
  2.  
  3. #Show the plot 
  4. plt.show(fig1) 

然后是预测的百分比变化vs实际的百分比变化,值得注意的是,这里的预测相对实际来说波动更大,这是模型可以提高的部分:

  1. Y_daybefore, Y_test, delta_predict, delta_real, fig2 = price_change(Y_daybefore, Y_test, y_predict) 
  2.  
  3. #Show the plot 
  4. plt.show(fig2) 

最终模型表现是这样的:

  1. Precision: 0.62 
  2. Recall: 0.553571428571 
  3. F1 score: 0.584905660377 
  4. Mean Squared Error: 0.0430756924477 

怎么样,看完有没有跃跃欲试呢?

代码下载地址:

https://github.com/llSourcell/ethereum_future/blob/master/A%20Deep%20Learning%20Approach%20to%20Predicting%20Cryptocurrency%20Prices.ipynb

原视频地址:

https://www.youtube.com/watch?v=G5Mx7yYdEhE

【本文是51CTO专栏机构大数据文摘的原创译文,微信公众号“大数据文摘( id: BigDataDigest)”】

     大数据文摘二维码

戳这里,看该作者更多好文

【编辑推荐】

  1. 手把手:扫描图片又大又不清晰?这个Python小程序帮你搞定!
  2. 教材太贵?一小段Python代码帮你自动翻页和扫描
  3. 人生苦短,为何一定要学Python?(文末有赠书)
  4. AI = 神经网络?这8个技术就不是!
  5. 有这5小段代码在手,轻松实现数据可视化(Python+Matplotlib)
【责任编辑:赵宁宁 TEL:(010)68476606】

点赞 0
分享:
大家都在看
猜你喜欢

热门职位+更多