基于LSTM多维度特征的资金流预测

项目背景

本篇主要是使用天池比赛中余额宝资金流的数据,已知在2013年7月1日至2014年8月31日内余额宝每日申购和赎回的资金流,通过使用python对数据进行处理之后用LSTM进行回归预测,再进行回测来检验模型。

观察数据进行处理

首先是对这427天数据的整体分布进行观察,申购的资金流分布如下:
这里插入图片描述
可以看出数据的整体趋势是先逐渐上升,到200天之后有大幅度的跌涨(可能跟春节有关),然后在经过一段降幅后逐渐趋于稳定。根据此情况,可将数据按时间分为三个阶段,即增长期(2013.7—2013.12),降幅期(2014.1—2014.3)和平稳期(2014.4—2014.8)。

然后,观察用户操作情况,发现每月的用户数都在增长,但有一部分用户却在427天内未做过任何操作,便将这一部分的用户作为“异常值”而删除。将其余用户进行保留,尽管其余用户有的操作金额可能并不多,但这也是一部分信息的体现,就先将其进行保留处理。

再导入其余的三张表:mfd_day_share_interest,user_profile_table和mfd_bank_shibor,发现mdf_day_share_interest和user_profile_table中的数值正常无明显的缺失值和异常值,而mfd_bank_shibor在周六周日含有缺失值,要想保障数据的准确,不论是取平均值还是别的方式发现都不太令人满意,因此也就暂未处理(如果有朋友能有合适的方法多多留言哦~)。

在user_profile_table表中发现了,此次交易用户来自7座城市,因此可以考虑将用户按城市进行划分,表中也含有12星座的信息,可能也跟星座有关(人的性格啊等等等),还含有男性和女性的标记,也可按性别进行划分。

然后,我们将user_balance_table,user_profile_table和mdf_day_share_interest这三张表进行合并,对user_profile_table表中的相关信息进行One-hot编码,便于后续的相关性分析。

特征选择

对已合并的表用Sperman方法进行相关性分析,发现user_balance_table中的其余属性分别与申购和赎回的相关性都大于0.6而user_profile_table和mfd_bank_shibor中的属性与申购和赎回的相关性小于0.6,因此就选择相关性大于0.6的强相关性属性作为特征。

预测purchase和redeem时,均选取report_date、tBalance、yBalance、direct_purchase_amt、purchase_bal_amt、purchase_bank_amt、consume_amt、transafer_amt、tftobal_amt、tftocard_amt、share_amt、total_purchase_amt这十一个属性作为特征来进行预测。

代码实现

这里只放上了purchase的预测代码,redeem与此相同

# 加载数据分析常用库
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
#% matplotlib inline
import os
import tensorflow as tf
from sklearn.preprocessing import StandardScaler


tf.reset_default_graph()

pd.set_option('display.max_columns',20)
pd.set_option('display.max_rows',31)

trian_path =  './test_data_purchase.csv'
df11 = pd.read_csv(trian_path)
//获取11个属性和目标值
data = df11.iloc[:,1:13]
ss = StandardScaler()
data_sd = ss.fit_transform(data)
plt.figure(figsize=(24,8))
plt.plot(data_sd[:,:11])
plt.plot(data_sd[:,11],label = 'target',color='red')
plt.legend(loc = 'upper left',fontsize = 24)
plt.show()

data = np.array(df11.ix[:,1:13])
# 清除图层,否则会报错
tf.reset_default_graph()

然后,设置参数

rnn_unit = 10  # 隐层数量
input_size = 11
output_size = 1
lr = 0.0006  # 学习率
epochs = 500

构建获取训练集数据的函数,使用均差的方法对数据进行标准化

# 获取训练集
def get_train_data(batch_size=14, time_step=2,train_begin=0, train_end=len(data)):
    batch_index = []
    data_train = data[train_begin:train_end]
    normalized_train_data = (
        data_train-np.mean(data_train, axis=0))/np.std(data_train, axis=0)  # 标准化
    train_x, train_y = [], []  # 训练集
    for i in range(len(normalized_train_data)-time_step):
        if i % batch_size == 0:
            batch_index.append(i)
        x = normalized_train_data[i:i+time_step, :11]
        y = normalized_train_data[i:i+time_step, 11, np.newaxis]
        train_x.append(x.tolist())
        train_y.append(y.tolist())
    batch_index.append((len(normalized_train_data)-time_step))
    return batch_index, train_x, train_y

定义输入输出层权重、偏置和LSTM

# 输入层、输出层权重、偏置
weights = {
    'in': tf.Variable(tf.random_normal([input_size, rnn_unit])),
    'out': tf.Variable(tf.random_normal([rnn_unit, 1]))
    }
biases = {
    'in': tf.Variable(tf.constant(0.1, shape=[rnn_unit, ])),
    'out': tf.Variable(tf.constant(0.1, shape=[1, ]))
    }

def lstm(X):
    batch_size = tf.shape(X)[0]
    time_step = tf.shape(X)[1]
    w_in = weights['in']
    b_in = biases['in']
    input = tf.reshape(X, [-1, input_size])  # 需要将tensor转成2维进行计算,计算后的结果作为隐藏层的输入
    input_rnn = tf.matmul(input, w_in)+b_in
    # 将tensor转成3维,作为lstm cell的输入
    input_rnn = tf.reshape(input_rnn, [-1, time_step, rnn_unit])
    cell = tf.contrib.rnn.BasicLSTMCell(rnn_unit)
    init_state = cell.zero_state(batch_size, dtype=tf.float32)
    output_rnn, final_states = tf.nn.dynamic_rnn(
        cell, input_rnn, initial_state=init_state, dtype=tf.float32)
    output = tf.reshape(output_rnn, [-1, rnn_unit])
    w_out = weights['out']
    b_out = biases['out']
    pred = tf.matmul(output, w_out)+b_out
    return pred, final_states

构建训练Lstm的函数,用最小二乘loss作为目标函数来预测

def train_lstm(batch_size=14, time_step=2,epochs=epochs, train_begin=0, train_end=len(data)):
    X = tf.placeholder(tf.float32, shape=[None, time_step, input_size])
    Y = tf.placeholder(tf.float32, shape=[None, time_step, output_size])
    batch_index, train_x, train_y = get_train_data(batch_size, time_step, train_begin, train_end)
    with tf.variable_scope("sec_lstm"):
        pred, _ = lstm(X)
    loss = tf.reduce_mean(
        tf.square(tf.reshape(pred, [-1])-tf.reshape(Y, [-1])))
    train_op = tf.train.AdamOptimizer(lr).minimize(loss)
    saver = tf.train.Saver(tf.global_variables(), max_to_keep=15)

    with tf.Session() as sess:
        sess.run(tf.global_variables_initializer())
        for i in range(epochs):  # 这个迭代次数,可以更改,越大预测效果会更好,但需要更长时间
            for step in range(len(batch_index)-1):
                _, loss_ = sess.run([train_op, loss], feed_dict={X: train_x[batch_index[
                                    step]:batch_index[step+1]], Y: train_y[batch_index[step]:batch_index[step+1]]})
            if (i+1)%50==0:
                print("Number of epochs:", i+1, " loss:", loss_)
                print("model_save: ", saver.save(sess, 'model_save/modle.ckpt'))
        print("The train has finished")

开始训练

with tf.variable_scope('train'):
    train_lstm()

获取测试集的数据

def test_get_test_data(time_step=14,data=data,test_begin=0):
    data_test = data[test_begin:]
    mean = np.mean(data_test, axis=0)
    std = np.std(data_test, axis=0)
    normalized_test_data = (data_test-mean)/std  # 标准化
    size = (len(normalized_test_data)+time_step-1)//time_step  # 有size个sample
    test_x = []
    for i in range(size-1):
        x = normalized_test_data[i*time_step:(i+1)*time_step, :11]        
        test_x.append(x.tolist())    
    test_x.append((normalized_test_data[(i+1)*time_step:, :11]).tolist())
    return test_x,mean,std

构建预测模型

# 预测模型
def prediction(time_step=14):
    X=tf.placeholder(tf.float32, shape=[None,time_step,input_size])
    test_x,mean,std = test_get_test_data(time_step=14,data=data,test_begin=0)
    
    with tf.variable_scope("sec_lstm",reuse=True):
        pred,_=lstm(X)
    saver=tf.train.Saver(tf.global_variables())
    with tf.Session() as sess:
        #参数恢复
        module_file = tf.train.latest_checkpoint('model_save')
        saver.restore(sess, module_file)
        # 测试训练
        prev_seq=test_x[0]
        test_predict=[]
        for step in range(len(test_x)-1):   
          if step <= len(test_x)-1:
              prev_seq=test_x[step]
          
          prob=sess.run(pred,feed_dict={X:[prev_seq]})   
          

          predict=prob.reshape((-1))
          test_predict.extend(predict)
          
        test_y=np.array(test_y)*std[11]+mean[11]
        test_predict=np.array(test_predict)*std[11]+mean[11]
        acc=np.average(np.abs(test_predict[:-30]-test_y[:len(test_predict)-30]))  #mean absolute error
        print("The MAE of this predict:",acc)
        #以折线图表示结果
        plt.figure(figsize=(15,12))
        plt.plot(list(range(len(test_predict))), test_predict, color='b',label = 'prediction')
        plt.plot(list(range(len(test_y))), test_y,  color='r',label = 'origin')
        plt.legend(fontsize=15)
        plt.show()
        return test_predict

开始预测

with tf.variable_scope('train',reuse=True):
    result = prediction()

得到结果预测图

在这里插入图片描述
赎回的原始数据和预测数据的情况
在这里插入图片描述
赎回的原始数据和预测数据的情况

回测的效果看起来不错,不过如果要用这个方法做未来30天的预测的话,也就需要能得到特征值尽量准确或者提高模型的泛化能力。

参考了以下博客的框架:
Tensorflow实例:利用LSTM预测股票每日最高价(一)

  • 3
    点赞
  • 72
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
基于 LSTM 模型进行多个时间序列预测的思路如下: 1. 数据准备:将多个时间序列数据合并成一个多维数组,每个时间序列对应一个维度。注意,不同时间序列的数据可能具有不同的尺度,需要对数据进行归一化处理,使其具有相同的尺度。 2. 数据划分:将数据集划分为训练集和测试集。对于多维时间序列数据,需要同时考虑多个时间序列的长度,并根据需要预测的时间点确定数据划分的方式。一种可能的方式是将每个时间序列的前面一部分作为训练集,后面一部分作为测试集,然后对训练集和测试集进行合并。 3. 模型建立:使用 LSTM 模型对多维时间序列数据进行建模。对于多维时间序列数据,可以使用多输入 LSTM 模型或多输出 LSTM 模型。多输入 LSTM 模型将每个时间序列作为一个输入,多输出 LSTM 模型将每个时间序列作为一个输出。在模型中可以使用多个 LSTM 层和全连接层,以提高模型的拟合能力。 4. 模型训练:使用训练集对 LSTM 模型进行训练,优化模型的参数。在训练过程中,可以使用交叉验证等技术来评估模型的性能。 5. 模型预测:使用训练好的 LSTM 模型对测试集进行预测,得到预测值。对于多维时间序列数据,可以同时预测多个时间序列的未来值。需要注意的是,模型预测结果可能存在误差,需要进行后续的评估和调整。 6. 模型评估:使用测试集的真实值和模型预测值进行比较,计算预测误差指标(如均方误差、平均绝对误差等),评估模型的性能。如果模型的性能不够理想,可以考虑调整模型的结构或参数,或者使用其他模型进行建模。 需要注意的是,在进行多个时间序列预测时,需要考虑不同时间序列之间的相互影响关系。比如,一个时间序列的值可能会受到其他时间序列值的影响,这就需要考虑如何在模型中建立这种关系。另外,多维时间序列数据的维度可能较高,需要注意维度灾难问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

辰阳星宇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值