时间序列预测

一、统计工具statsmodels

 statsmodels工具提供了 统计计算,包括描述性统计、统计模型的估计和推断

子模块:

1、回归模型: 线性回归、广义线性模型、线性混合效应模型

2、方差分析:(ANOVA)通过分析研究不同来源的变异对总变异的贡献大小,从而确定可控因素对研究结果影响力的大小 

3、时间序列分析:AR、ARMA、ARIMA

包名:import statsmodels.api as sm

# 使用tsa对沪市指数进行分析:trend, seasonal, residual
# 数据加载
data = pd.read_csv('shanghai_index_1990_12_19_to_2020_03_12.csv', usecols=['Timestamp', 'Price'])
print(data.head)
# to_datetime 转换为pandas中的日期格式
data.Timestamp = pd.to_datetime(data.Timestamp)
data = data.set_index('Timestamp')
print(data)
# 数据转换成数值类型
data['Price'] = data['Price'].apply(pd.to_numeric, errors='ignore')
# 进行线性插补缺漏值
data.Price.interpolate(inplace=True)
#  返回三个部分 trend(趋势),seasonal(季节性)和residual (残留)
result = sm.tsa.seasonal_decompose(data.Price, freq=250)
result.plot()
plt.show()

pandas 时间戳转datetime类型->   pd.to_datetime(data.Timestamp)

pandas 转换数值类型 -> data['Price'].apply(pd.to_numeric,errors='ignore')

pandas 线性差缺补漏 -> data.Price.interpolate(inplace=True)   3 4  五  6

sm工具包对数据进行降解 -> sm.tsa.seasional_decompose(data.Price,freq=250)   freq= 1年内优先数据个数

tsa -> time series analysis 时间序列分析

二、AR(p)模型,自回归模型

通过这个时刻的前p个点,通过线性组合+白噪音来预测当前时刻的值

白噪音:时间序列中数值随机波动,这些波动会相互抵消,累计为0

三、MA(q)模型,滑动平均模型 

MA是通过历史白噪音进行线性组合来影响当前时间点

四、ARMA模型,自回归滑动平均模型

AR 解决当前数据与后期数据之间的关系,MA解决随机波动,既噪音问题

五、ARIMA模型,查分自回归滑动平均模型

模型步骤:

step1 观察时间序列,是否平稳

step2 对非平稳时间序列先进行d阶差分运算,化为平稳序列

step3 使用ARIMA(p,d,q)模型进行训练模拟,找到最优的(p,d,q)训练好模型

step4 只用ARIMA进行预测,并对差分还原 

step5 查看aic  

aic准则-> 赤池消息准则,是衡量统计模型拟合好坏的标准,数值越小代表模型拟合越好

# -*- coding: utf-8 -*-
# 沪市指数走势预测,使用时间序列ARMA
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from statsmodels.tsa.arima_model import ARIMA
import statsmodels.api as sm
import warnings
from itertools import product
from datetime import datetime, timedelta
import calendar

warnings.filterwarnings('ignore')
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
# 数据加载
df = pd.read_csv('./shanghai_index_1990_12_19_to_2020_03_12.csv')
df = df[['Timestamp', 'Price']]

# 将时间作为df的索引
df.Timestamp = pd.to_datetime(df.Timestamp)
df.index = df.Timestamp
# 数据探索
print(df.head())
# 按照月,季度,年来统计
df_month = df.resample('M').mean()
df_Q = df.resample('Q-DEC').mean()
df_year = df.resample('A-DEC').mean()
print(df_month)

# 设置参数范围
ps = range(0, 5)
qs = range(0, 5)
ds = range(1, 2)
parameters = product(ps, ds, qs)
parameters_list = list(parameters)
# 寻找最优ARMA模型参数,即best_aic最小
results = []
best_aic = float("inf") # 正无穷
#--------->>>> 打擂法寻找网格最优组合 <<<<-----------
for param in parameters_list:
    try:
        #model = ARIMA(df_month.Price,order=(param[0], param[1], param[2])).fit()
        # SARIMAX 包含季节趋势因素的ARIMA模型
        model = sm.tsa.statespace.SARIMAX(df_month.Price,
                                order=(param[0], param[1], param[2]),
                                #seasonal_order=(4, 1, 2, 12),
                                enforce_stationarity=False,
                                enforce_invertibility=False).fit()

    except ValueError:
        print('参数错误:', param)
        continue
    aic = model.aic
    if aic < best_aic:
        best_model = model
        best_aic = aic
        best_param = param
    results.append([param, model.aic])
# 输出最优模型
print('最优模型: ', best_model.summary())

# 设置future_month,需要预测的时间date_list
df_month2 = df_month[['Price']]
future_month = 3
last_month = pd.to_datetime(df_month2.index[len(df_month2)-1])
date_list = []
for i in range(future_month):
    # 计算下个月有多少天
    year = last_month.year
    month = last_month.month
    if month == 12:
        month = 1
        year = year+1
    else:
        month = month + 1
    next_month_days = calendar.monthrange(year, month)[1]
    #print(next_month_days)
    last_month = last_month + timedelta(days=next_month_days)
    date_list.append(last_month)
print('date_list=', date_list)

# 添加未来要预测的3个月
future = pd.DataFrame(index=date_list, columns= df_month.columns)
df_month2 = pd.concat([df_month2, future])

# get_prediction得到的是区间,使用predicted_mean
df_month2['forecast'] = best_model.get_prediction(start=0, end=len(df_month2)).predicted_mean

# 沪市指数预测结果显示
plt.figure(figsize=(30,7))
df_month2.Price.plot(label='实际指数')
df_month2.forecast.plot(color='r', ls='--', label='预测指数')
plt.legend()
plt.title('沪市指数(月)')
plt.xlabel('时间')
plt.ylabel('指数')
plt.show()

df.resample(‘M’).mean() 均值

六、LSTM 长短记忆网络

跟RNN区别,避免常规的RNN多层网络梯度消失问题

1、引入三门函数:

输入门、遗忘门、输出门来控制输入、记忆值和输出

输入门,当前时刻网络状态有多少信息需要保存到内部状态

遗忘门,决定过去的状态信息多少需要丢弃

输出门,决定当前时刻内部状态有多少信息需要输出到外部状态

2、输入输出

# LSTM设置

n_steps_in = 3     #输入时间步  输入3个时刻 

n_features = 2     #输入特征维度 每个时刻2个维度

n_steps_out = 2   # 输出时间步

epochs = 500     # 迭代次数

LSTM(50,  activation='relu',  input_shape = (n_steps, n_features))

出现欠拟合   -> 增加迭代次数epochs = 5000     # 迭代次数

# 使用LSTM预测沪市指数
import numpy as np
import pandas as pd
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import LSTM
from keras.layers import Dropout
from pandas import DataFrame
from pandas import concat
from itertools import chain
from sklearn.metrics import mean_squared_error
import matplotlib.pyplot as plt


# 转化为可以用于监督学习的数据
def get_train_set(data_set, timesteps_in, timesteps_out=1):
    train_data_set = np.array(data_set)
    reframed_train_data_set = np.array(series_to_supervised(train_data_set, timesteps_in, timesteps_out).values)
    print(reframed_train_data_set)
    print(reframed_train_data_set.shape)
    train_x, train_y = reframed_train_data_set[:, :-timesteps_out], reframed_train_data_set[:, -timesteps_out:]
    # 将数据集重构为符合LSTM要求的数据格式,即 [样本数,时间步,特征]
    train_x = train_x.reshape((train_x.shape[0], timesteps_in, 1))
    return train_x, train_y

"""
将时间序列数据转换为适用于监督学习的数据
给定输入、输出序列的长度
data: 观察序列
n_in: 观测数据input(X)的步长,范围[1, len(data)], 默认为1
n_out: 观测数据output(y)的步长, 范围为[0, len(data)-1], 默认为1
dropnan: 是否删除NaN行
返回值:适用于监督学习的 DataFrame
"""
def series_to_supervised(data, n_in=1, n_out=1, dropnan=True):
    n_vars = 1 if type(data) is list else data.shape[1]
    df = DataFrame(data)
    cols, names = list(), list()
    # input sequence (t-n, ... t-1)
    for i in range(n_in, 0, -1):
        cols.append(df.shift(i))
        names += [('var%d(t-%d)' % (j + 1, i)) for j in range(n_vars)]
    # 预测序列 (t, t+1, ... t+n)
    for i in range(0, n_out):
        cols.append(df.shift(-i))
        if i == 0:
            names += [('var%d(t)' % (j + 1)) for j in range(n_vars)]
        else:
            names += [('var%d(t+%d)' % (j + 1, i)) for j in range(n_vars)]
    # 拼接到一起
    agg = concat(cols, axis=1)
    agg.columns = names
    # 去掉NaN行
    if dropnan:
        agg.dropna(inplace=True)
    return agg


# 使用LSTM进行预测
def lstm_model(source_data_set, train_x, label_y, input_epochs, input_batch_size, timesteps_out):
    model = Sequential()
    
    # 第一层, 隐藏层神经元节点个数为128, 返回整个序列
    model.add(LSTM(128, return_sequences=True, activation='tanh', input_shape=(train_x.shape[1], train_x.shape[2])))
    # 第二层,隐藏层神经元节点个数为128, 只返回序列最后一个输出
    model.add(LSTM(128, return_sequences=False))
    model.add(Dropout(0.5))
    # 第三层 因为是回归问题所以使用linear
    model.add(Dense(timesteps_out, activation='linear'))
    model.compile(loss='mean_squared_error', optimizer='adam')

    # LSTM训练 input_epochs次数
    res = model.fit(train_x, label_y, epochs=input_epochs, batch_size=input_batch_size, verbose=2, shuffle=False)

    # 模型预测
    train_predict = model.predict(train_x)
    #test_data_list = list(chain(*test_data))
    train_predict_list = list(chain(*train_predict))

    plt.plot(res.history['loss'], label='train')
    plt.show()
    print(model.summary())
    plot_img(source_data_set, train_predict)

# 呈现原始数据,训练结果,验证结果,预测结果
def plot_img(source_data_set, train_predict):
    plt.figure(figsize=(24, 8))
    # 原始数据蓝色
    plt.plot(source_data_set[:, -1], c='b')
    # 训练数据绿色
    plt.plot([x for x in train_predict], c='g')
    plt.legend()
    plt.show()

# 设置观测数据input(X)的步长(时间步),epochs,batch_size
timesteps_in = 3
timesteps_out = 3
epochs = 500
batch_size = 100
data = pd.read_csv('./shanghai_index_1990_12_19_to_2020_03_12.csv')
data_set = data[['Price']].values.astype('float64')
# 转化为可以用于监督学习的数据
train_x, label_y = get_train_set(data_set, timesteps_in=timesteps_in, timesteps_out=timesteps_out)

# 使用LSTM进行训练、预测
lstm_model(data_set, train_x, label_y, epochs, batch_size, timesteps_out=timesteps_out)

LabelEncoder 将分类特征进行标签编码

数据切分 # LSTM 不能用train_test_split切分,因为时间序列不连续

               # XGBost 可以, 样本是相对独立的

values = reframed.values

n_train_hours = int(len(values)*80)

train = values[:n_train_hours,:]

test = values[n_train_hours:,:]

train_x,train_y = train[:,:-1],train[:,-1]

test_x,test_y = test[:,:-1],train[:,-1]

 

七、总结

时间序列是结构化数据,每个时间戳有一个数值

应用场景:

1、金融股票价格预测,资金流入流出预测

2、运维中异常检测,日活月活时间序列异常检测

预测方法:(快)

统计学方法: ARMA,ARIMA

from statsmodels.tsa.arima_model import ARMA

使用RNN/LSTM 进行预测(多维度)

keras.layers.recurrent.LSTM(unit,activtion,return_sequences,input_shape)

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值