[LSTM]使用LSTM预测监控数据的数值

阅读 291
收藏 5
2018-08-14
原文链接:www.flyml.net

本次命题: 数值预测

上一篇文章我们的小题目是使用LSTM预测字符顺序的下一个字符。

命题虽然简单, 可是实际上应用范围也很广。 比如输入法里面, 就一定会用到相关的技术。 只不过不一定是LSTM, 肯定也不止一维特征。这次这个命题相对来说, 比较实际一些:从历史预测监控数据预测即将来临的监控指标的数值。

比如下图就是本站在友盟上面的监控数据。 最右边的虚线部分就是友盟进行的预测的数值:

本文代码特别鸣谢:https://blog.csdn.net/aliceyangxi1987/article/details/73420583

预测代码做了简单修改就迁移过来直接用了。

具体修改与讨论放在最后进行。

获取数据并展示

因为X轴坐标太挤,显示不出来, 所以没有显示在这里。

数据介绍:

  • 这个是我司某个监控指标的数值。 具体名字就不说啦:D
  • 时间跨度: 一个月
  • 粒度: 每个小时一个数值
  • 数据下载: 链接

可以看到, 在前面一段时间, 数值的跳动是比较规律的。 当然中间也有一个异常点。 只不过后面忽然出现了几个大的波峰。 如果是异常检测, 在这里就一定要把后面几个波峰给挑出来。

开始炼丹 / 训练模型

完整代码如下:

import numpy
import matplotlib.pyplot as plt
from pandas import read_csv
import math
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import LSTM
from sklearn.preprocessing import MinMaxScaler
from sklearn.metrics import mean_squared_error
%matplotlib inline
 
 
# 加载数据
dataframe = read_csv("monitor-metics-data.csv", usecols=[1])
dataset = dataframe.values
# 将整型变为float
dataset = dataset.astype('float32') # numpy.ndarray 类型
 
# 创建matrix类型的数据集
def create_dataset(dataset, look_back=1):
    dataX, dataY = [], []
    for i in range(len(dataset)-look_back-1):
        a = dataset[i:(i+look_back), 0]
        dataX.append(a)
        dataY.append(dataset[i + look_back, 0])
    return numpy.array(dataX), numpy.array(dataY)
 
# fix random seed for reproducibility
numpy.random.seed(7)
 
 
# 数据正则化, 方法: Min Max
scaler = MinMaxScaler(feature_range=(0, 1))
dataset = scaler.fit_transform(dataset)
 
# 【注意】因为在我们的周期是小时, 基本上按天进行变动, 可以设置为24. 
# 实际上, 也可以设置为1,误差比想象中的小很多
look_back = 24 
 
# 切分train / test 数据 
train_size = int(len(dataset) * 0.67)
test_size = len(dataset) - train_size
train, test = dataset[0:train_size,:], dataset[train_size:len(dataset),:]
 
# 开始构建数据集
trainX, trainY = create_dataset(train, look_back)
testX, testY = create_dataset(test, look_back)
# 注意这里的reshape的操作。 
trainX = numpy.reshape(trainX, (trainX.shape[0], trainX.shape[1], 1))
testX = numpy.reshape(testX, (testX.shape[0], testX.shape[1], 1))
 
# 开始训练模型
# 可以把epochs 训练次数加大, 当前时间不足, 只进行了10次
model = Sequential()
model.add(LSTM(4, input_shape=(look_back,1)))
model.add(Dense(1))
model.compile(loss='mean_squared_error', optimizer='adam')
model.fit(trainX, trainY, epochs=10, batch_size=2, verbose=2)
 
 
# 为了展示区别, 训练、测试数据都预测。 
trainPredict = model.predict(trainX)
testPredict = model.predict(testX)
 
# invert predictions
trainPredict = scaler.inverse_transform(trainPredict)
trainY = scaler.inverse_transform([trainY])
testPredict = scaler.inverse_transform(testPredict)
testY = scaler.inverse_transform([testY])
 
# 计算误差值/RMSE
trainScore = math.sqrt(mean_squared_error(trainY[0], trainPredict[:,0]))
print('Train Score: %.2f RMSE' % (trainScore))
testScore = math.sqrt(mean_squared_error(testY[0], testPredict[:,0]))
print('Test Score: %.2f RMSE' % (testScore))
 
# 绘图
# plot baseline and predictions
def plot_result() :
    raw = scaler.inverse_transform(dataset)
 
    x = read_csv("monitor-metics-data.csv", usecols=[0]).values.tolist()
 
    # shift train predictions for plotting
    trainPredictPlot = numpy.empty_like(dataset)
    trainPredictPlot[:, :] = numpy.nan
    trainPredictPlot[look_back:len(trainPredict)+look_back, :] = trainPredict
 
    # shift test predictions for plotting
    testPredictPlot = numpy.empty_like(dataset)
    testPredictPlot[:, :] = numpy.nan
    testPredictPlot[len(trainPredict)+(look_back*2)+1:len(dataset)-1, :] = testPredict
 
    #创建绘图对象,figsize参数可以指定绘图对象的宽度和高度,单位为英寸,一英寸=80px
    fig, ax = plt.subplots(figsize=(20,5))
 
    raw_line, = plt.plot(x,raw, "m--", linewidth=1, label="Raw Data")   
    train_line, = plt.plot(x,trainPredictPlot, "b-", linewidth=1, label="Train Predict") 
    test_line, = plt.plot(x,testPredictPlot, "g-", linewidth=1, label="Test Predict") 
 
    plt.legend(handles=[raw_line, train_line, test_line])
 
    xticks=list(range(0,len(x),40))
    xlabels=[x[t] for t in xticks]
    xticks.append(len(x))
    xlabels.append(x[-1])
    ax.set_xticks(xticks)
    ax.set_xticklabels(xlabels, rotation=40)
 
    plt.show()
plot_result()
 

如上图所示:

  • 红色虚线是原始数据,
  • 蓝色为训练数据的预测值。重合度一般
  • 绿色为测试数据的预测值。 虽然波峰突然起来, 预测的值也相应的升高。 只不过跟真实值还是有区别。 这就为我们使用LSTM做异常检测(Anomaly Detection) 打下了基础。

改动的地方

  • look_back

    原文的look_back 是1, 个人觉得在实际生产之中, 应该不会这样使用

    根据我们已知的时间窗口周期, 改成了24。

  • numpy.reshape / input_shape

    原文代码:

    # reshape input to be [samples, time steps, features]
    trainX = numpy.reshape(trainX, (trainX.shape[0], 1, trainX.shape[1]))
    testX = numpy.reshape(testX, (testX.shape[0], 1, testX.shape[1]))
     
    # ... 中间略
    model.add(LSTM(4, input_shape=(1, look_back)))
     

    我的修改:

    trainX = numpy.reshape(trainX, (trainX.shape[0], trainX.shape[1], 1))
    testX = numpy.reshape(testX, (testX.shape[0], testX.shape[1], 1))
    # ... 中间略
    model.add(LSTM(4, input_shape=(look_back,1)))
     

    我的理解:

    1. 因为我们的数据的特征是一维, 因此features的值应该是1
    2. 而我们往回看的时间窗口实际值是look_back的值。 在create_dateset函数里面, 是的数据集的宽度就是look_back, 即trainX.shape[1] == look_back
  • plot_result函数

    原来的绘图函数太简陋, 在这里做了好一些优化,比如:

    • 图放大
    • 有legend
    • x坐标的值间隔显示

本文原创, 转摘需要注明出处:

[LSTM]使用LSTM预测监控数据的数值

评论