zoukankan      html  css  js  c++  java
  • ARIMA模型---时间序列分析---温度预测

    (图片来自百度)

    数据

    分析数据第一步还是套路------画图

    数据看上去比较平整,但是由于数据太对看不出具体情况,于是将只取前300个数据再此画图

    这数据看上去很不错,感觉有隐藏周期的意思

    代码

    #coding:utf-8
    import csv
    import matplotlib.pyplot as plt
    
    def read_csv_data(aim_list_1, aim_list_2, file_name):
        i = 0
        csv_file = csv.reader(open(file_name,'r'))
        for data in csv_file:
            if (i == 0):
                i += 1
                continue
            aim_list_1.append(float(data[1]))
            aim_list_2.append(data[3])
        return
    def plot_picture(x, y):
        plt.xlabel('x')
        plt.ylabel('y')
        plt.plot(x, y)
        plt.show()
        return
    if __name__ == '__main__':
        temp = []
        tim = []
        file_name = 'C:/Users/lichaoxing/Desktop/testdata.csv'
        read_csv_data(temp, tim, file_name)
        plot_picture(tim[:300], temp[:300])

    使用ARIMA模型(ARMA)

    第一步观察数据是否是平稳序列,通过上图可以看出是平稳的

    如果不平稳,则需要进行预处理,方法有   对数变换    差分

    对于平稳的时间序列可以直接使用ARMA(p, q)模型进行拟合

    ARMA (p, q) :  AR(p) + MA(q)

    此时参数p和q的确定可以通过观察ACF和PACF图来确定

    通过观察PACF图可以看出,阶数为9也就是p=9,这里ACF图看出自相关呈现震荡下降收敛,但是怎么决定出q,我没太明白,这里姑且拍脑袋才一个吧就q=3

    但是这里我遇到了一个问题,没有搞懂,就是平稳的序列,如果我进行一阶差分后应该仍然是平稳的序列,但是这个时候我又画了一个ACF与PACF图,竟然是下图这样,lag的范围是-0.04到0.04(不懂)


    lag的范围是-0.04到0.04的问题原因(修改于再次使用此模型)

    原因:

    当时,我使用的是一阶差分,也就是让数据的后一个值减去前一个值得到新的值,这样就会导致第一个值变为缺失值(下面的数据是再此使用此模型时的数据,与原博客数据无关

    就是因为此处的值为缺失值,导致绘制ACF与PACF时数据有问题而无法成功显示

    解决办法,在绘制上述图形前,将第一个数据去除:

    dta= dta.diff(1)
    dta = dta.truncate(before= ym[1])#删除第一个缺失值

    其实还有就是使用ADF检验,得到的结果如图,这个p值很小===》平稳

    画图代码

    def acf_pacf(temp, tim):
        x = tim
        y = temp
        dta = pd.Series(y, index = pd.to_datetime(x))
        fig = plt.figure(figsize=(9,6))
        ax1 = fig.add_subplot(211)
        fig = sm.graphics.tsa.plot_acf(dta,lags=50,ax=ax1)
        ax2 = fig.add_subplot(212)
        fig = sm.graphics.tsa.plot_pacf(dta,lags=50,ax=ax2)
        show()

    ADF检验代码

    def test_stationarity(timeseries):
        dftest = adfuller(timeseries, autolag='AIC')
        return dftest[1]

    这里先使用ARMA(9,3)来实验测试一下效果,取前300个数据中的前250个作为train,后面的作为test

    效果

    可以说这个模型是真的强大,预测的还是十分准确的

    代码

    def test_300(temp, tim):
    
        x = tim[0:300]
        y = temp[0:300]
        dta = pd.Series(y[0:249], index = pd.to_datetime(x[0:249]))
    
        fig = plt.figure(figsize=(9,6))
        ax1 = fig.add_subplot(211)
        fig = sm.graphics.tsa.plot_acf(dta,lags=30,ax=ax1)
        ax2 = fig.add_subplot(212)
        fig = sm.graphics.tsa.plot_pacf(dta,lags=30,ax=ax2)
    
        arma_mod = sm.tsa.ARMA(dta, (9, 3)).fit(disp = 0)
    
        predict_sunspots = arma_mod.predict(x[200], x[299], dynamic=True)
    
        fig, ax = plt.subplots(figsize=(9, 6))
        ax = dta.ix[x[0]:].plot(ax=ax)
        predict_sunspots.plot(ax=ax)
    
        show()

    其实,可以通过代码来自动的选择p和q的值,依据BIC准则,目标就是bic越小越好

    代码

    def proper_model(timeseries, maxLag):
        init_bic = 100000000
        init_properModel = None
        for p in np.arange(maxLag):
            for q in np.arange(maxLag):
                model = ARMA(timeseries, order=(p, q)) 
                try:
                    results_ARMA = model.fit(disp = 0, method='css')
                except:
                    continue
                bic = results_ARMA.bic
                if bic < init_bic:
                    init_properModel = results_ARMA
                    init_bic = bic
        return init_properModel

    遇到的问题,预测时predict函数没怎么使用明白

    当写于某些预测区间的时候,会报 “start”或“end”的相关错误,还有一个函数forcast,这个函数使用就是forcast(N):预测后面N个值

    返回的是预测值(array型)标准误差(array型)置信区间(array型)

    还有:

    对于构造时间序列,时间可以是时间格式:如 “2018-01-01”  或者就是个时间戳,在用时间戳的时候,其实在序列里它会自动识别时间戳,并加上起始时间1970-01-01 00:00:01

    形式

    附录(代码)

    预测一序列中某一点的值

    #coding:utf-8
    import csv
    import time
    import pandas as pd
    import numpy as np
    from statsmodels.tsa.arima_model import ARMA
    import argparse
    import warnings
    
    warnings.filterwarnings('ignore')
    def timestamp_datatime(value):
        value = time.localtime(value)
        dt = time.strftime('%Y-%m-%d %H:%M',value)
        return dt
    
    def time_timestamp(my_date):
        my_date_array = time.strptime(my_date,'%Y-%m-%d %H:%M')
        my_date_stamp = time.mktime(my_date_array)
        return my_date_stamp
    
    def read_csv_data(aim_list_1, aim_list_2, file_name):
        i = 0
        csv_file = csv.reader(open(file_name,'r'))
        for data in csv_file:
            if (i == 0):
                i += 1
                continue
            aim_list_1.append(float(data[1]))   #1:温度  2:湿度
            dt = int(data[3])
            aim_list_2.append(dt)
        return
    
    def proper_model(timeseries, maxLag):
        init_bic = 100000000
        init_properModel = None
        for p in np.arange(maxLag):
            for q in np.arange(maxLag):
                model = ARMA(timeseries, order=(p, q))   #bug
                try:
                    results_ARMA = model.fit(disp = 0, method='css')
                except:
                    continue
                bic = results_ARMA.bic
                if bic < init_bic:
                    init_properModel = results_ARMA
                    init_bic = bic
        return init_properModel
    
    def test_300(temp, tim, time_in):
        
        x = []
        y = []
        end_index = len(tim)
        for i in range(0, len(tim)):
            if (time_in - (tim[i]) < 300):
                end_index = i
                break
        if (end_index < 100):
            x = tim[0: end_index]
            y = temp[0: end_index]
        else:
            x = tim[end_index - 100: end_index]
            y = temp[end_index - 100: end_index]
        
        tidx = pd.DatetimeIndex(x, freq='infer')
        dta = pd.Series(y, index = tidx)
        print(dta)
        arma_mod = proper_model(dta, 9)
    
        predict_sunspots = arma_mod.forecast(1)
        return predict_sunspots[0]
    def predict_temperature(file_name, time_in):
    
        temp = []
        tim = []
        read_csv_data(temp, tim, file_name)
        
        result_temp = test_300(temp, tim, time_in)
        
        return result_temp
    if __name__ == '__main__':
        
        parser = argparse.ArgumentParser()
        parser.add_argument('-f', action='store', dest='file_name')
        parser.add_argument('-t', action='store', type = int, dest='time_')
    
        args = parser.parse_args()
        file_name = args.file_name
        time_in = args.time_
    
        result_temp = predict_temperature(file_name, time_in)
    
        print ('the temperature is %f ' % result_temp)

    在上面的代码中,预测某一点的值我采用序列中此点的前100个点作为训练集

    如果给出待预测的多个点,由于每次都要计算模型的p和q以及拟合模型,时间会很慢,于是考虑将给定的待预测时间点序列切割成小段,使每一段中最大与最小的时间间隔在某一范围内

    在使用forcast(n)函数一次预测多点,然后在预测值中找到与待预测的时间值相近的值,速度大大提升,思路如图

    代码

    #coding:utf-8
    import csv
    #import time
    import pandas as pd
    import numpy as np
    from statsmodels.tsa.arima_model import ARMA
    import warnings
    
    warnings.filterwarnings('ignore')
    
    def proper_model(timeseries, maxLag):
        init_bic = 1000000000
        init_p = 1
        init_q = 1
        for p in np.arange(maxLag):
            for q in np.arange(maxLag):
                model = ARMA(timeseries, order=(p, q))
                try:
                    results_ARMA = model.fit(disp = 0, method='css')
                except:
                    continue
                bic = results_ARMA.bic
                if bic < init_bic:
                    init_p = p
                    init_q = q
                    init_bic = bic
        return init_p, init_q
    
    def read_csv_data(file_name, clss = 1):
        i = 0
        aim_list_1 = [] #temperature(1) or humidity(2)
        aim_list_2 = [] #time
        csv_file = csv.reader(open(file_name,'r'))
        for data in csv_file:
            if (i == 0):
                i += 1
                continue
            aim_list_1.append(float(data[clss]))
            dt = int(data[3])
            aim_list_2.append(dt)
        
        tidx = pd.DatetimeIndex(aim_list_2, freq = None)
        dta = pd.Series(aim_list_1, index = tidx)
        init_p, init_q = proper_model(dta[:aim_list_2[100]], 9)
        return init_p, init_q, aim_list_2, dta
    
    def for_kernel(p, q, tim, dta, tmp_time_list, result_dict):
        interval = 20
        end_index = len(tim) - 1
        for i in range(0, len(tim)):
            if (tmp_time_list[0]["time"] - tim[i] < tim[1] - tim[0]):
                end_index = i
                break
    
        if (end_index < 100):
            dta = dta.truncate(after = tim[end_index])
        else:
            dta = dta.truncate(before= tim[end_index - 101], after = tim[end_index])
    
        arma_mod = ARMA(dta, order=(p, q)).fit(disp = 0, method='css')
        #为未来interval天进行预测, 返回预测结果, 标准误差, 和置信区间
        predict_sunspots = arma_mod.forecast(interval)
        ####################################
        for tim_i in tmp_time_list:
            for tim_ in tim:
                if tim_i["time"] - tim_ >= 0 and tim_i["time"] - tim_ < tim[1] - tim[0]:
                    result_dict[tim_i["time"]] = predict_sunspots[0][tim.index(tim_) - end_index]
        return
    
    def kernel(p, q, tim, dta, time_in_list):
        interval = 20
        time_first = time_in_list[0]
        det_time = tim[1] - tim[0]
        result_dict = {}
        tmp_time_list = []
        for time_ in time_in_list:
            if time_first["time"] + det_time * interval > time_["time"]:
                tmp_time_list.append(time_)
                continue
    
            time_first = time_
            for_kernel(p, q, tim, dta, tmp_time_list, result_dict)
            tmp_time_list = []
            tmp_time_list.append(time_first)
        
        for_kernel(p, q, tim, dta, tmp_time_list, result_dict)
        
        return result_dict
    
    def predict_temperature(file_name, time_in_list, clss = 1):
        p, q, tim, dta = read_csv_data(file_name, clss)
    
        result_temp_dict = kernel(p, q, tim, dta, time_in_list)
        
        return result_temp_dict
    
    def predict_humidity(file_name, time_in_list, clss = 2):
        p, q, tim, dta = read_csv_data(file_name, clss)
        result_humi_dict = kernel(p, q, tim, dta, time_in_list)
    
        return result_humi_dict
    
    if __name__ == '__main__':
        
    
        file_name = "testdata.csv"
        time_in = [{"time":1530419271,"temp":"","humi":""},{"time":1530600187,"temp":"","humi":""},{"time":1530825809,"temp":"","humi":""}]
    
        #time_in = [{"time":1530600187,"temp":"","humi":""},]
        result_temp = predict_temperature(file_name, time_in)
        print(result_temp)

    由于后续又改动了需求,需要预测温度以及湿度,完成了项目在github

    https://github.com/xinglicha0/armamodel


     

  • 相关阅读:
    深入理解计算机系统 第六章 存储器层次结构 第二遍
    深入理解计算机系统 第六章 存储器层次结构
    深入理解计算机系统 第八章 异常控制流 Part2 第二遍
    深入理解计算机系统 第八章 异常控制流 part2
    深入理解计算机系统 第八章 异常控制流 Part1 第二遍
    深入理解计算机系统 第八章 异常控制流 part1
    深入理解计算机系统 第三章 程序的机器级表示 Part2 第二遍
    深入理解计算机系统 第三章 程序的机器级表示 part2
    深入理解计算机系统 第三章 程序的机器级表示 Part1 第二遍
    深入理解计算机系统 第三章 程序的机器级表示 part1
  • 原文地址:https://www.cnblogs.com/xinglichao/p/9620490.html
Copyright © 2011-2022 走看看