详细分析及预测过程
一、背景及目的
(1)背景介绍
为了实现信息化发展,建设自动化办公系统、人力资源管理系统财务管理系统、企业信息门户系统等大型应用系统。某企业应用系统日常运行时,会对底层软硬件造成负荷,显著地影响应用系统的性能。任何一种资源负载过大,都可能会引起应用系统性能下降甚至瘫痪。因此需要关注服务器、数据库、中间件和存储设备的运行状态,及时了解当前应用系统的负载情况,以便提前预防,确保系统安全稳定运行。
(2)目的
- 针对历史磁盘数据,采用时间序列分析方法,预测系统服务器磁盘已使用空间大小;
- 根据用户需要设置不同预警等级,将预测值与实际值进行比较,对结果进行预警判断,为系统管理员提供定制化的预警提示。
二、分析思路
本项目的主要分析思路如下图所示。
(1)数据平稳性:给出一个随机时间序列,首先可以通过该序列的时间路径图来粗略地判断数据是否平稳。
一个平稳的时间序列在图形上往往表现出一种围绕其均值不断波动的过程;而不平稳的时间序列往往表现出在不同的时间段具有不同的均值。
平稳性检验:
- 时序图检验:其依据是均值方差为常数,且始终在一常数值附近随机波动,波动范围有限,无明显趋势及周期特征;
- 自相关图检验:随着延迟期数增加,自相关系数衰减到0
平稳性的含义:一个时间序列剔除不变的均值和时间趋势以后,剩余的序列为0均值,同方差,也就是白噪声。
(2)白噪声:随机变量Xt和Xs的协方差为0,则为纯随机过程,若其期望为0,方差为常数,则称为白噪声过程。白噪声序列的AC和PAC的值都落在两倍标准差范围内,且p值>0.05(即序列为白噪声),其序列没意义,不能建立ARIMA模型。
(3)模型识别:ARIMA(p,d,q)称为差分自回归移动平均模型,AR是自回归,p为自回归项;MA为移动平均,q为移动平均项数,d为时间序列成为平稳时所做的差分次数。
所谓的ARIMA模型是指将非平稳时间序列转为平稳的时间序列,然后将因变量仅对它的滞后值以及随机误差项的现值和滞后值进行回归所建立的模型。
ARIMA的基本思想:将预测对象随时间推移而形成的数据序列视为一个随机序列,用一定的数学模型来近似描述这个序列,这个模型一旦识别后,就可以从时间序列的过去值及现在值预测未来值。
(4)模型检验:建立好模型后,需要对过去值和现在值进行检验,比较模型输出值与过去值相差是否很大,从而得知模型是否合理。
(5)模型预测:对模型进行检验并且合理后,可以利用模型来预测未来某一段时间的值。
三、代码详解
(1)首先导入需要用到的包
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from statsmodels.tsa.stattools import adfuller as ADF
from statsmodels.stats.diagnostic import acorr_ljungbox
from statsmodels.tsa.arima_model import ARIMA #自回归求和移动平均模型
import seaborn as sns
import statsmodels.api as sm
from statsmodels.graphics.api import qqplot
%matplotlib inline
(2)查看原始数据形式
df=pd.read_excel('discdata.xls') #读取数据
df.head() #显示数据前5行
结果显示如下表所示
表中的属性解释如下
属性名称 | 属性说明 |
---|---|
SYS_NAME | 系统名称 |
NAME | 资产名称 |
TARGET_ID | 属性的标识号 |
DESCRIPTION | 属性标识的说明 |
ENTITY | 具体的属性 |
VALUE | 采集到的值 |
COLLECTTIME | 采集的时间 |
其中,属性的标识号183表示磁盘容量大小(固定值),184表示磁盘已使用容量大小
(3)数据预处理
因为NAME属性和SYS_NAME是一致的,因此可以删除NAME属性,同时DESCRIPTION属性和TARGET_ID属性是一致的,也删除DESCRIPTION属性;再将COLLECTTIME属性设置为索引
x=[1,3] #定义需要删除的列号
df=df.drop(df.columns[x],axis=1) #删除对建模无关的属性
df=df.set_index(['COLLECTTIME']) #将时间设置为索引。很重要!!!没有这一句代码,接下来的模型识别中p,q找不到
df.head() #显示数据5行
(4)查看原始数据时序图
因为TARGET_ID有183和184两种情况,ENTITY有C和D 两种情况,因此共有4种不同的时序图。为了实现不同的TARGET_ID和ENTITY输入,项目中定义一个函数,通过对函数输入不同的值(183或184、C或D)可以得到不同的时序图。
def input_target_entity(target_id,entity):
if target_id==184:
df_=df.loc[df.TARGET_ID==184]
if entity=='C':
d=df_.loc[df_.ENTITY=='C:\\']
if entity=='D':
d=df_.loc[df_.ENTITY=='D:\\']
else:
df_=df.loc[df.TARGET_ID==183]
if entity=='C':
d=df_.loc[df_.ENTITY=='C:\\']
if entity=='D':
d=df_.loc[df_.ENTITY=='D:\\']
data_display(d) #调用数据显示函数
def data_display(d):
data=d.VALUE
data=data.iloc[:len(data)-5] #最后5条数据用于预测
plt.plot(data,label='Actual Value')
plt.title('Trends in raw data')
plt.xlabel('Time')
plt.ylabel('Number')
plt.xticks(rotation=60) #横坐标刻度旋转60°
stability_whitenoise(data) #调用稳定性白噪声检测函数
通过对input_target_entity()传入参数,可以得到不同的时序图,此处以输入184、D为例,其显示的时序图如下
(5)稳定性、白噪声检测
定义一个函数,通过传入数据作为参数从而对数据进行稳定性和白噪声检测
def stability_whitenoise(x): #数据平稳性检测以及白噪声检验函数
train=x.iloc[:len(x)] #不对最后5个数据进行检测,此5个数据用来预测
diff=0 #差分阶数初始化
adf=ADF(train) #用ADF检验来对数据进行检验,其返回结果有adf值和p值等等
while adf[1]>=0.05: #如果ADF返回p值大于等于0.05
diff=diff+1 差分阶数加1
adf=ADF(train.diff(diff).dropna()) #再对一阶差分做差分处理,此时已为2阶差分
print('原始数据序列经过{}差分后归于平稳,对应的p值为{}'.format(diff,adf[1])) #经差分处理后可得到d值
#白噪声检验:只有时间序列不是白噪声才可以做分析
[[lb],[p]]=acorr_ljungbox(train,lags=1)
if p<0.05:
print('原始序列为非白噪声序列,对应的p值为,',p)
else:
print('原始序列为白噪声序列,对应p值为,',p)
上面一段为原始数据白噪声检验,接下来是一阶差分后的白噪声检验
[[lb],[p]]=acorr_ljungbox(train.diff().dropna(),lags=1)
if p<0.05:
print('一阶差分序列为非白噪声序列,对应p值为,',p)
else:
print('一阶差分序列为白噪声序列,对应p值为,',p)
model_recognition(train) #调用模型识别函数
acorr_ljungbox函数详细说明参见acorr_ljungbox
(6)模型识别
此过程主要是确定ARIMA(p,d,q)中的p和q参数
def model_recognition(train):
p_max=int(len(train)/10) #确定p的最大值
q_max=int(len(train)/10) #确定q的最大值
bic_matrix=[] #BIC准则矩阵
for p in range(p_max+1): #range(5)等价于range(0,5),其值为[0,1,2,3,4]没有5
tmp=[]
for q in range(q_max+1):
try:
tmp.append(ARIMA(train,(p,1,q)).fit().bic)
except:
tmp.append(None)
bic_matrix.append(tmp)
bic_matrix=pd.DataFrame(bic_matrix)
p,q=bic_matrix.stack().idxmin() #idxmin()目的是提取最小值所在的位置
print(bic_matrix)
print('BIC最小的p值和q值分别为{}、{}'.format(p,q))
model_test(p,q,train)
在代码中,得到的bic_matrix矩阵如下所示
p,q的取值是根据这个矩阵中最小值的位置来确定,右图可知p、q均为1
(7)模型检验
此过程主要对历史数据进行预测,将预测数据和实际数据进行残差计算,最后利用残差计算得到的结果进行白噪声检验。如果不满足白噪声检验,说明残差还存在有用的信息,需要修改模型或者进一步提取。
def model_test(p,q,train):
lagnum=12 #残差延迟个数
arima=ARIMA(train,(p,1,q)).fit() #建立ARIMA(p,1,q)模型
train_pred=arima.predict(typ='levels') #对训练数据进行预测
pred_error=(train_pred-train).dropna() #残差计算
#又进行白噪声检验
lb,p=acorr_ljungbox(pred_error,lags=lagnum)
m=(p<0.05).sum()
if m>0:
print('模型ARIMA(1,1,1)不符合白噪声检验')
else:
print('模型ARIMA(1,1,1)符合白噪声检验')
输出的结果如下所示
由此知道模型建立和参数的提取是正确的,下一步可以进行预测
(8)模型预测
现在需要对D盘未来5天进行预测
def model_predict(train_pred,arima):
predict=arima.predict('2014-11-12','2014-11-17',typ='levels')
train_pred=train_pred
plt.plot(predict,'r+',label='Predict')
plt.plot(train_pred,'r',label='Past predict')
plt.legend(loc=4)
预测的结果如下图所示,图中蓝色曲线为过去值,红色曲线为过去值的模型预测值,红色‘+’为未来5天的预测
从图中可以看出,预测值与真实值的趋势是一致的,因此对未来几天的预测可信度是很高的
附:对184C盘进行预测结果如下所示
(9)模型的应用
此过程主要将模型设置不同的预警等级,使得系统管理员更加方便的根据预警等级对系统磁盘使用情况进行判断,阈值设置表如下
预测已使用空间率 | 预警等级 |
---|---|
85% | 一级 |
90% | 二级 |
95% | 三级 |
已知磁盘的最大容量为52323320
def model_application(predict):
predict=predict.to_frame()
predict.columns=['VALUE']
print(predict)
for i in predict.VALUE:
i=int(i)
if i < 44474822:
print('系统正常')
elif i< 47090988:
print('一级预警')
elif i<49707154:
print('二级预警')
else:
print('三级预警')
预测那5天的得到数据等级显示如下所示
因此,我们可以对预测的数据进行预警等级的判断,从而使得系统管理员更加方便的了解系统磁盘的使用情况。
项目中的模型采用的是历史数据进行建模,但是随着时间的推移,每天会定时地将新增数据加入初始建模数据中。在正常的情况下,模型需要重新调整。由于建立模型过程比较复杂,且系统磁盘已使用大小每天的变化量相对很小,对于整个模型的预测影响较小。因此,结合实际业务情况,每半个月对模型进行一次调整。
总结
对项目进行总结有以下几点:
- 对**ARIMA(p,d,q)**模型的建模过程、模型的参数选择有了一定的了解
- 对于时间序列的数据预测过程有了一定的认识,以后遇到时间序列预测问题也有一定的解决思路
- 熟悉一些基本概念,如:数据平稳性、白噪声数据等,同时也知道了怎么解决数据的不平稳性以及知道了白噪声数据的处理方式。