【数据挖掘】时间序列模型处理指南(二)

news2024/12/25 9:25:40

一、说明

        本文是一个系列文章的第二部分,本文将用股票数据进行时间序列分析为例,对时间分析的方法、过程,进行详细阐述。

二、前文章节

        在文章第一部分种:【数据挖掘】时间序列模型处理(一)_无水先生的博客-CSDN博客

七、时序模型示例:预测股票价格

        我们将使用新德国基金(GF)的历史股价来尝试预测未来五个交易日的收盘价。(您可以与 数据集和笔记本。

7.1 导入数据

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
sns.set()

from sklearn.metrics import r2_score, median_absolute_error, mean_absolute_error
from sklearn.metrics import median_absolute_error, mean_squared_error, mean_squared_log_error

from scipy.optimize import minimize
import statsmodels.tsa.api as smt
import statsmodels.api as sm

from tqdm import tqdm_notebook

from itertools import product

def mean_absolute_percentage_error(y_true, y_pred):
    return np.mean(np.abs((y_true - y_pred) / y_true)) * 100

import warnings
warnings.filterwarnings('ignore')

%matplotlib inline

DATAPATH = 'data/stock_prices_sample.csv'

data = pd.read_csv(DATAPATH, index_col=['DATE'], parse_dates=['DATE'])
data.head(10)

        首先,我们将导入一些在整个分析过程中有帮助的库。此外,我们需要定义平均百分比误差 (MAPE),因为这将是我们的误差指标。

        然后,我们将导入数据集和前十个条目。您应该获得:

数据集的前 10 个条目 

        如您所见,我们有一些条目涉及与新德国基金(GF)不同的股票。此外,我们有一个关于日内信息的条目,但我们只想要日终 (EOD) 信息。

7.2  清理数据

data = data[data.TICKER != 'GEF']
data = data[data.TYPE != 'Intraday']

drop_cols = ['SPLIT_RATIO', 'EX_DIVIDEND', 'ADJ_FACTOR', 'ADJ_VOLUME', 'ADJ_CLOSE', 'ADJ_LOW', 'ADJ_HIGH', 'ADJ_OPEN', 'VOLUME', 'FREQUENCY', 'TYPE', 'FIGI']

data.drop(drop_cols, axis=1, inplace=True)

data.head()

        首先,我们将删除不需要的条目。然后,我们将删除不需要的列,因为我们只想关注股票的收盘价。

        准备进行数据分析:for exploratory data analysis.

7.3. 指数移动平均(EDA)

# Plot closing price

plt.figure(figsize=(17, 8))
plt.plot(data.CLOSE)
plt.title('Closing price of New Germany Fund Inc (GF)')
plt.ylabel('Closing price ($)')
plt.xlabel('Trading day')
plt.grid(False)
plt.show()

        我们将绘制数据集整个时间段的收盘价。

        您应该获得:

   新德国基金(GF)的收盘价。

      

        显然,这不是一个静止的过程,很难判断是否存在某种季节性。

7.4. 移动平均线

        让我们使用移动平均模型来平滑我们的时间序列。为此,我们将依靠一个辅助函数,该函数将在指定的时间窗口内运行移动平均模型,并将绘制结果平滑曲线:

def plot_moving_average(series, window, plot_intervals=False, scale=1.96):

    rolling_mean = series.rolling(window=window).mean()
    
    plt.figure(figsize=(17,8))
    plt.title('Moving average\n window size = {}'.format(window))
    plt.plot(rolling_mean, 'g', label='Rolling mean trend')
    
    #Plot confidence intervals for smoothed values
    if plot_intervals:
        mae = mean_absolute_error(series[window:], rolling_mean[window:])
        deviation = np.std(series[window:] - rolling_mean[window:])
        lower_bound = rolling_mean - (mae + scale * deviation)
        upper_bound = rolling_mean + (mae + scale * deviation)
        plt.plot(upper_bound, 'r--', label='Upper bound / Lower bound')
        plt.plot(lower_bound, 'r--')
            
    plt.plot(series[window:], label='Actual values')
    plt.legend(loc='best')
    plt.grid(True)
    
#Smooth by the previous 5 days (by week)
plot_moving_average(data.CLOSE, 5)

#Smooth by the previous month (30 days)
plot_moving_average(data.CLOSE, 30)

#Smooth by previous quarter (90 days)
plot_moving_average(data.CLOSE, 90, plot_intervals=True)

        使用五天的时间窗口,我们得到:

前一个交易周的平滑曲线

        我们几乎看不到趋势,因为它太接近实际曲线了。让我们平滑上个月和上一季度来比较结果。

按上个月(30 天)平滑

与上一季度(90 天)平滑

        现在趋势更容易发现。请注意 30 天和 90 天趋势在结束时如何显示下降曲线。这可能意味着该股票可能会在接下来的几天内下跌。

7.5. 指数平滑

        现在,让我们使用指数平滑来查看它是否可以获得更好的趋势。

def exponential_smoothing(series, alpha):

    result = [series[0]] # first value is same as series
    for n in range(1, len(series)):
        result.append(alpha * series[n] + (1 - alpha) * result[n-1])
    return result
  
def plot_exponential_smoothing(series, alphas):
 
    plt.figure(figsize=(17, 8))
    for alpha in alphas:
        plt.plot(exponential_smoothing(series, alpha), label="Alpha {}".format(alpha))
    plt.plot(series.values, "c", label = "Actual")
    plt.legend(loc="best")
    plt.axis('tight')
    plt.title("Exponential Smoothing")
    plt.grid(True);

plot_exponential_smoothing(data.CLOSE, [0.05, 0.3])

        在这里,我们使用 0.05 和 0.3 作为平滑因子的值。随意尝试其他值,看看结果如何。

        应用于模型的指数平滑。|图片:马可·佩谢罗

        如您所见,alpha 值 0.05 平滑了曲线,同时拾取了大部分上升和下降趋势。

        现在,让我们使用双指数平滑

7.6. 双指数平滑

def double_exponential_smoothing(series, alpha, beta):

    result = [series[0]]
    for n in range(1, len(series)+1):
        if n == 1:
            level, trend = series[0], series[1] - series[0]
        if n >= len(series): # forecasting
            value = result[-1]
        else:
            value = series[n]
        last_level, level = level, alpha * value + (1 - alpha) * (level + trend)
        trend = beta * (level - last_level) + (1 - beta) * trend
        result.append(level + trend)
    return result

def plot_double_exponential_smoothing(series, alphas, betas):
     
    plt.figure(figsize=(17, 8))
    for alpha in alphas:
        for beta in betas:
            plt.plot(double_exponential_smoothing(series, alpha, beta), label="Alpha {}, beta {}".format(alpha, beta))
    plt.plot(series.values, label = "Actual")
    plt.legend(loc="best")
    plt.axis('tight')
    plt.title("Double Exponential Smoothing")
    plt.grid(True)
    
plot_double_exponential_smoothing(data.CLOSE, alphas=[0.9, 0.02], betas=[0.9, 0.02])

你会得到:

应用于模型的双指数平滑。|图片:马可·佩谢罗

再次,尝试不同的 alpha  beta 组合以获得更好看的曲线。

7.7. 建模

        如前所述,我们必须将我们的系列变成一个静止的过程才能对其进行建模。因此,让我们应用 Dickey-Fuller 测试来查看它是否是一个平稳过程:

def tsplot(y, lags=None, figsize=(12, 7), syle='bmh'):
    
    if not isinstance(y, pd.Series):
        y = pd.Series(y)
        
    with plt.style.context(style='bmh'):
        fig = plt.figure(figsize=figsize)
        layout = (2,2)
        ts_ax = plt.subplot2grid(layout, (0,0), colspan=2)
        acf_ax = plt.subplot2grid(layout, (1,0))
        pacf_ax = plt.subplot2grid(layout, (1,1))
        
        y.plot(ax=ts_ax)
        p_value = sm.tsa.stattools.adfuller(y)[1]
        ts_ax.set_title('Time Series Analysis Plots\n Dickey-Fuller: p={0:.5f}'.format(p_value))
        smt.graphics.plot_acf(y, lags=lags, ax=acf_ax)
        smt.graphics.plot_pacf(y, lags=lags, ax=pacf_ax)
        plt.tight_layout()
        
tsplot(data.CLOSE, lags=30)

# Take the first difference to remove to make the process stationary
data_diff = data.CLOSE - data.CLOSE.shift(1)

tsplot(data_diff[1:], lags=30)

        您应该看到:

        Dicke-Fuller检验应用于揭示非平稳模型的模型。 

通过 Dickey-Fuller 检验,时间序列毫不奇怪地是非平稳的。此外,查看自相关图,我们看到它非常高,似乎没有明显的季节性。

为了摆脱高自相关并使过程平稳,让我们采用第一个差异(代码块中的第 23 行)。我们简单地从自身中减去滞后一天的时间序列,得到:

使时序模型静止 

        我们的系列现在是固定的,我们可以开始建模了。

7.8. 萨里马

#Set initial values and some bounds
ps = range(0, 5)
d = 1
qs = range(0, 5)
Ps = range(0, 5)
D = 1
Qs = range(0, 5)
s = 5

#Create a list with all possible combinations of parameters
parameters = product(ps, qs, Ps, Qs)
parameters_list = list(parameters)
len(parameters_list)

# Train many SARIMA models to find the best set of parameters
def optimize_SARIMA(parameters_list, d, D, s):
    """
        Return dataframe with parameters and corresponding AIC
        
        parameters_list - list with (p, q, P, Q) tuples
        d - integration order
        D - seasonal integration order
        s - length of season
    """
    
    results = []
    best_aic = float('inf')
    
    for param in tqdm_notebook(parameters_list):
        try: model = sm.tsa.statespace.SARIMAX(data.CLOSE, order=(param[0], d, param[1]),
                                               seasonal_order=(param[2], D, param[3], s)).fit(disp=-1)
        except:
            continue
            
        aic = model.aic
        
        #Save best model, AIC and parameters
        if aic < best_aic:
            best_model = model
            best_aic = aic
            best_param = param
        results.append([param, model.aic])
        
    result_table = pd.DataFrame(results)
    result_table.columns = ['parameters', 'aic']
    #Sort in ascending order, lower AIC is better
    result_table = result_table.sort_values(by='aic', ascending=True).reset_index(drop=True)
    
    return result_table

result_table = optimize_SARIMA(parameters_list, d, D, s)

#Set parameters that give the lowest AIC (Akaike Information Criteria)
p, q, P, Q = result_table.parameters[0]

best_model = sm.tsa.statespace.SARIMAX(data.CLOSE, order=(p, d, q),
                                       seasonal_order=(P, D, Q, s)).fit(disp=-1)

print(best_model.summary())

        现在,对于 SARIMA,我们首先需要定义一些参数和其他参数的值范围,以生成 p、q、d、P、Q、D、S 的所有可能组合的列表。

        现在,在上面的代码单元格中,我们有 625 种不同的组合。我们将尝试每种组合,并用每种组合训练 SARIMA,以找到性能最佳的模型。这可能需要一段时间,具体取决于计算机的处理能力。

        完成此操作后,我们将打印出最佳模型的摘要,您应该看到:

时间序列模型的打印结果。 

        我们最终可以预测未来五个交易日的收盘价,并评估模型的平均绝对百分比误差(MAPE)。

        在这种情况下,我们的MAPE为0.79%,这是非常好的。

        有关数据科学的更多信息C 均值聚类说明

7.9. 将预测价格与实际数据进行比较

# Make a dataframe containing actual and predicted prices
comparison = pd.DataFrame({'actual': [18.93, 19.23, 19.08, 19.17, 19.11, 19.12],
                          'predicted': [18.96, 18.97, 18.96, 18.92, 18.94, 18.92]}, 
                          index = pd.date_range(start='2018-06-05', periods=6,))


#Plot predicted vs actual price

plt.figure(figsize=(17, 8))
plt.plot(comparison.actual)
plt.plot(comparison.predicted)
plt.title('Predicted closing price of New Germany Fund Inc (GF)')
plt.ylabel('Closing price ($)')
plt.xlabel('Trading day')
plt.legend(loc='best')
plt.grid(False)
plt.show()

        现在,为了将我们的预测与实际数据进行比较,我们可以从雅虎财经获取财务数据并创建一个数据帧。

        然后,我们制作一个图来查看我们离实际收盘价有多远:

预测(橙线)和实际(蓝线)收盘价的比较 

        看来我们的预测有点偏差。事实上,预测的价格基本上是持平的,这意味着我们的模型可能表现不佳。

        同样,这不是由于我们的程序,而是由于预测股票价格基本上是不可能的。

        从第一个项目中,我们学习了在使用SARIMA建模之前使时间序列静止的整个过程。这是一个漫长而乏味的过程,需要大量的手动调整。

        现在,让我们介绍Facebook的先知。它是Python和R中可用的预测工具。该工具允许专家和非专家以最小的努力生成高质量的预测。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/705315.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spring Boot中的@EnableWebSocketMessageBroker注解是什么,原理,以及如何使用

Spring Boot中的EnableWebSocketMessageBroker注解是什么&#xff0c;原理&#xff0c;以及如何使用 WebSocket是一种在Web浏览器和Web服务器之间进行双向通信的技术。在传统的HTTP通信中&#xff0c;客户端向服务器发送请求&#xff0c;服务器响应请求&#xff0c;然后关闭连…

黑马Java项目实战-瑞吉外卖-笔记01

视频地址&#xff1a;黑马程序员Java项目实战《瑞吉外卖》&#xff0c;轻松掌握springboot mybatis plus开发核心技术的真java实战项目_哔哩哔哩_bilibili资料下载&#xff1a;百度网盘【黑马程序员-Java瑞吉外卖-企业级项目实战-平台实战开发】 黑马Java项目实战-瑞吉外卖-笔…

PHP表单传值和文件上传:深入解析数据交互与文件处理技术

目录 表单传值 为什么要表单传值&#xff1f; 表单传值的方式 GET传值 POST传值 GET和POST两种传参方式的不同&#xff1a; PHP接受数据的三种方式 PHP处理复选框数据 复选框表单的命名方式 复选框数据的接受形式 复选框数据的常见处理 复选框细节&#xff1a; 文件…

区块链技术如何改变Web3认证的现状?

随着加密货币和区块链技术的迅猛发展&#xff0c;Web3钱包成为了数字经济时代中的重要组成部分。Web3钱包是一种工具&#xff0c;用于存储、管理和交互加密货币及其他数字资产&#xff0c;以及与去中心化应用程序&#xff08;DApp&#xff09;进行交互。它们是实现Web3.0理念的…

chatgpt赋能python:标题:免费的Python编辑器:优秀的编程工具免费获取

标题&#xff1a;免费的Python编辑器&#xff1a;优秀的编程工具免费获取 Python是一种高级编程语言&#xff0c;被广泛应用于数据科学、机器学习、Web开发和科学计算等领域。Python编程简单易学&#xff0c;更重要的是它的灵活性和扩展性&#xff0c;吸引了越来越多的开发者加…

自适应混沌粒子群算法(Matlab)

在上一个博客中作者介绍了标准粒子群及其实现&#xff0c;并给出了许多改进方向&#xff0c;那么从这一期开始就会陆续更新关于粒子群的改进&#xff0c;这一期的改进主要有三个方向&#xff0c;1.混沌初始化粒子群 2 非线性调整惯性权重 3 学习因子动态变化。 下面将对这些改进…

网络犯罪分子在新的代理劫持活动中劫持脆弱的SSH服务器

一个活跃的金融活动针对的是脆弱的SSH服务器&#xff0c;以隐蔽地将它们纳入一个代理网络。 "Akamai研究员Allen West在周四的一份报告中说&#xff1a;"这是一个活跃的活动&#xff0c;攻击者利用SSH进行远程访问&#xff0c;运行恶意脚本&#xff0c;隐蔽地将受害…

正点原子stm32HAL库学习_基础篇_1

单片机简介 STM32芯片分类 ST中文社区网&#xff1a;https://www.stmcu.org.cn/ ST官网&#xff1a;https://www.st.com/content/st_com/en.html STM32命名规则 数据手册 在设计STM32F103 原理图的时候&#xff0c;我们需要用到一个非常重要的文档&#xff1a;STM32F103 数据 …

Tomcat的概念及部署

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、Tomcat的概述1.tomcat 概述2.tomcat 的主要特点 二、Tomcat的核心组件1.核心组件关系图2.核心组件的介绍2.1 Web容器2.2 servlet容器2.3 JSP容器2.4 Tomcat核心…

7、Redis复制(replica)

Redis复制(replica) 是什么&#xff1f; 就是主从复制&#xff0c;master以写为主&#xff0c;Slave以读为主。当master数据变化的时候&#xff0c;自动将新的数据异步同步到其它slave数据库 读写分离 容灾恢复 数据备份 水平扩容支撑高并发 案例演示 架构说明 一个Master两个…

SQL-每日一题【182.查找重复的电子邮箱】

题目 表: Person 编写一个 SQL 查询来报告所有重复的电子邮件。 请注意&#xff0c;可以保证电子邮件字段不为 NULL。 以 任意顺序 返回结果表。 查询结果格式如下例。 示例 1: 解题思路 前置知识 count&#xff08;&#xff09; 1.count(*) &#xff1a;统计所有的行数&a…

KMeans算法实现图像分割

1. Kmeans聚类算法简介 由于具有出色的速度和良好的可扩展性&#xff0c;Kmeans聚类算法算得上是最著名的聚类方法。Kmeans算法是一个重复移动类中心点的过程&#xff0c;把类的中心点&#xff0c;也称重心(centroids)&#xff0c;移动到其包含成员的平均位置&#xff0c;然后重…

数据结构和算法-2023.06.29

斐波那契数列 初衷&#x1f481;&#x1f3fb; 说来也是惭愧&#xff0c;入行这么久了&#xff0c;一直没有仔细去思考为什么去做这个&#xff0c;之前一直游想法去好好学学数据结构和算法&#xff0c;一直苦于是重点学习Docker、K8S、JVM&#xff0c;多线程&#xff0c;或者是…

SpringBoot整合Redis缓存管理

1. 添加 Spring Data Redis 依赖启动器。在 chapter06 项目的 pom.xml 文件中添加 Spring Data Redis 依赖 启动器。 <!-- 引入整合 Redis 缓存的依赖启动器 --> <dependency> <groupId> org.springframework.boot </groupId> <artifactId>…

【单片机】STM32F103C8T6单片机,OLED 1.3寸 IIC OLED,STM32F103单片机,I2C OLED

文章目录 main.coled.coled.hOLED_Font.h 效果&#xff1a; main.c #include "sys.h" #include "usart.h" #include "OLED.h"int main(void) {NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); /* 设置NVIC中断分组2:2位抢占优…

C/C++图形库EasyX保姆级使用教程(一) Microsoft Visual Studio 2022和EasyX的下载及安装使用

C/C图形库EasyX保姆级使用教程 第一章 Microsoft Visual Studio 2022和EasyX的下载及安装使用 文章目录 C/C图形库EasyX保姆级使用教程前言一、图形库【EasyX】是什么&#xff1f;二、2.EasyX图形库和Microsoft Visual Studio 2022的安装1.Microsoft Visual Studio 2022&#…

详细讲述,人工智能、机器学习、深度学习、神经网络、自然语言处理、AIGC之间的关系...

人工智能&#xff08;Artificial Intelligence&#xff0c;AI&#xff09;是计算机科学中一个庞大的研究领域&#xff0c;旨在为计算机创造类似人类智能的功能&#xff0c;例如学习、推理、解决问题、识别模式、理解自然语言等。AI的核心目标是使计算机能够执行那些通常需要人类…

sql读取数据直接存成pandas

导包 import pymysql import pandas as pd获取mysql链接 def get_db():#打开数据库连接db pymysql.connect(host*.*.*.*,port3306,user "wws",passwd "yourpasswd",db "youdb")return db db get_db()写sql 读数据保存 sql "select…

【技术分享】RK356X Debian/Ubuntu 系统安装Docker

本文基于IDO-SBC3528主板演示Debian/Ubuntu 系统任何安装Docker&#xff0c;方法适用于RK3568全系列产品。 IDO-SBC3528-V1采用RK3568四核64位开发的智能主板&#xff0c;可作为RK3568开发评估板&#xff0c;支持8G大内存&#xff1b;支持PCIE2.0接口&#xff0c;可扩展大容量…

数据结构——直接插入排序与希尔排序(图示+文字详解)

内容包括&#xff1a;排序的代码实现&#xff0c;排序原理详解&#xff0c;代码详解&#xff0c;图示 part 1&#xff1a;直接插入排序 代码实现&#xff1a; void InsertSort(int* a, int n) {int i 0;for (i 0; i < n - 1; i){int end i;int tmp a[i 1];while (en…