【经典必学】时间序列数据探索

在时间序列数据中,拟合机器学习模型之前有一些重要的事项需要考虑。

  • 数据中的趋势
  • 季节性
  • 异常值
  • 长期周期
  • 常数方差
  • 突发变化

以下是正文内容,包括对代码部分的注释和总结:

# 导入所需的库
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn
seaborn.set()  # 设置 Seaborn 的绘图样式
%matplotlib inline  # 在 Jupyter Notebook 中启用内联绘图

# 输入数据文件位于 "../input/" 目录下
from subprocess import check_output
print(check_output(["ls", "../input"]).decode("utf8"))  # 列出 "../input/" 目录下的文件

# 读取训练数据和测试数据
train = pd.read_csv("../input/bitcoin_price_Training - Training.csv")
test = pd.read_csv("../input/bitcoin_price_1week_Test - Test.csv")

# 打印训练数据和测试数据的形状
print(train.shape)
print(test.shape)

# 打印训练数据的前几行
train.head()

# 打印训练数据的后几行
train.tail()

# 打印测试数据
test

# 将日期顺序反转,使其按时间顺序排列
train = train[::-1]  # 反转训练数据的行顺序
test = test[::-1]  # 反转测试数据的行顺序
train.head()  # 打印反转后的训练数据的前几行

# 将日期格式(字符串)转换为数值日期
# 图像 -- 定义一个函数(将日期转换为所需格式)并应用于每个日期
# 示例 -- f(x):= 应用 num
# f(April 28, 2013) = 2013-04-28
from dateutil.parser import parse
from datetime import datetime

def convert(date):
    holder = []
    for i in date:
        tp = parse(i).timestamp()  # 将字符串日期转换为时间戳
        dt = datetime.fromtimestamp(tp)  # 从时间戳转换为 datetime 对象
        holder.append(dt)
    return np.array(holder)

date = train['Date'].values  # 获取训练数据中的日期列
date_n = convert(date)  # 转换日期格式

# 桑性检查
print(len(date_n) == train.shape[0])  # 检查转换后的日期数量是否与原始数据行数相同

train['Date'] = date_n  # 将转换后的日期列赋值给训练数据
train.head()  # 打印前几行

# 将日期设置为索引
train = train.set_index('Date')  # 将 'Date' 列设置为索引
train.head()  # 打印前几行

# 检查缺失值
train.isnull().any()  # 检查训练数据中是否有缺失值

# 关闭价的可视化(原始数据和对数尺度)
# 思路:使用对数尺度的原因是它揭示了百分比变化
# 例如:
# 情况1)价格从 $10 上涨到 $15: 变化(增加)为 $5。增加率为 50%
# 情况2)价格从 $20 上涨到 $25: 变化(增加)为 $5。增加率为 25%
# 在这两种情况下,变化相同,但变化率不同
plt.figure(num=None, figsize=(20, 6))  # 创建一个 20x6 的图表
plt.subplot(1, 2, 1)  # 创建第一个子图
ax = train['Close'].plot(style=['-'])  # 绘制关闭价,线条样式为实线
ax.lines[0].set_alpha(0.3)  # 设置线条透明度
ax.set_ylim(0, np.max(train['Close'] + 100))  # 设置 y 轴的范围
plt.xticks(rotation=90)  # 设置 x 轴标签的旋转角度
plt.title("No scaling")  # 设置图表标题
ax.legend()  # 设置图例
plt.subplot(1, 2, 2)  # 创建第二个子图
ax = train['Close'].plot(style=['-'])  # 绘制关闭价,线条样式为实线
ax.lines[0].set_alpha(0.3)  # 设置线条透明度
ax.set_yscale('log')  # 设置 y 轴为对数尺度
ax.set_ylim(0, np.max(train['Close'] + 100))  # 设置 y 轴的范围
plt.xticks(rotation=90)  # 设置 x 轴标签的旋转角度
plt.title("logarithmic scale")  # 设置图表标题
ax.legend()  # 设置图例

# 上述图表的一些特征:
# 每个图表都显示了从 2016 年开始的上升趋势
# 没有明显的季节性
# 没有异常值
# 对数尺度的数据中有一些变化。这将通过滚动平均和标准差来确认

# 降低采样频率
# 绘制前一年的平均价格和年末价格
close = train['Close']  # 获取关闭价列
close.plot(alpha=0.5, style='-')  # 绘制关闭价,线条透明度为 0.5,样式为实线
close.resample('BA').mean().plot(style=':')  # 重新采样为每年末的平均值,线条样式为点线
close.asfreq('BA').plot(style='--')  # 重新采样为每年末的值,线条样式为虚线
plt.yscale('log')  # 设置 y 轴为对数尺度
plt.title("logarithmic scale")  # 设置图表标题
plt.legend(['close-price', 'resample', 'asfreq'], loc='upper left')  # 设置图例位置
# 'resample' -- 前一年的平均值
# 'asfreq' -- 年末的值

# 投资回报率(ROI)
# ROI = 100 * (close.shift(-365) / close - 1)
# ROI.plot()
# plt.ylabel('% Return on Investment');

# 移动平均:SMA 和 EMA
# 移动平均用于平滑数据以观察潜在趋势
# SMA(简单移动平均)计算某个跨度(N)的平均值,而 EMA(指数移动平均)则更多地强调近期数据点
rolling = close.rolling(200, center=True)  # 创建一个 200 天的滚动窗口,居中对齐

# 创建包含原始数据、200 天滚动平均和 200 天滚动标准差的 DataFrame
data = pd.DataFrame({'input': close, 
                     '200days rolling_mean': rolling.mean(), 
                     '200days rolling_std': rolling.std()})

# 绘制数据
ax = data.plot(style=['-', '--', ':'])  # 绘制数据,线条样式分别为实线、虚线和点线
ax.set_yscale('log')  # 设置 y 轴为对数尺度
ax.set_title("SMA on log scale")  # 设置图表标题
ax.lines[0].set_alpha(0.3)  # 设置原始数据线条的透明度

# 重要提示:价格变化的百分比标准差随时间变化不是一致的或非恒定的
ax = data.plot(style=['-', '--', ':'])  # 绘制数据,线条样式分别为实线、虚线和点线
ax.set_title("SMA on raw data")  # 设置图表标题
ax.lines[0].set_alpha(0.3)  # 设置原始数据线条的透明度

# 计算 365 天的指数移动平均
rolling = pd.Series.ewm(close, com=200)

# 创建包含原始数据、200 天指数移动平均和 200 天指数移动标准差的 DataFrame
data = pd.DataFrame({'input': close, 
                     '200days rolling_mean': rolling.mean(), 
                     '200days rolling_std': rolling.std()})

# 绘制数据
ax = data.plot(style=['-', '--', ':'])  # 绘制数据,线条样式分别为实线、虚线和点线
ax.set_yscale('log')  # 设置 y 轴为对数尺度
ax.set_title("EMA on log scale")  # 设置图表标题
ax.lines[0].set_alpha(0.3)  # 设置原始数据线条的透明度

# 绘制原始数据的图表
ax = data.plot(style=['-', '--', ':'])  # 绘制数据,线条样式分别为实线、虚线和点线
ax.set_title("EMA on raw data")  # 设置图表标题
ax.lines[0].set_alpha(0.3)  # 设置原始数据线条的透明度

# 滞后图(检查时间序列是否随机)
# 资源:http://www.itl.nist.gov/div898/handbook/eda/section3/lagplot.htm
# 在下图中,第一个轴表示 t(滞后),第二个轴表示 t+1
# 例如:如果数据是 [1, 4, 5, 3, 2],那么 y(t):= [1, 4, 5, 3, 2],y(t+1):= [4, 5, 3, 2]
# 从下图中可以看出,这表明非随机模式(图呈正线性)
# 数据中的非随机性揭示了我们可以使用自回归模型
from pandas.plotting import lag_plot
lag_plot(close)  # 绘制滞后图

# 自相关性
# 资源:http://www.itl.nist.gov/div898/handbook/eda/section3/eda35c.htm
# 上述滞后图显示了数据中的结构。为了量化 t 点和 t+1 点之间的相关性,使用了自相关性。
# 下图中的黑色线表示随机数据的期望值(因此相关性为 0),两条虚线分别表示 95% 和 99% 的置信区间。
# 图表显示了滞后小于 100 天时的强相关性。(滞后 0 的相关性总是 1)
from pandas.plotting import autocorrelation_plot
autocorrelation_plot(close)  # 绘制自相关图

# 部分自相关性
# 思路:部分自相关性仅描述 t-k 点(k 是滞后)对 t 点的直接影响,忽略它们之间的值(从 t-k+1 到 t-1 的值)。
# 自相关性则考虑了中间的值。部分自相关性将帮助我们确定自回归模型的阶数 p。 (AR(p))
# 参考:自相关性和部分自相关性的区别 https://stats.stackexchange.com/questions/129052/acf-and-pacf-formula
from pandas import Series
from statsmodels.graphics.tsaplots import plot_pacf
plot_pacf(close, lags=50)  # 绘制部分自相关图

# 自回归模型
# 滞后图和自相关性表明我们可以使用自回归模型来拟合数据
# 我们将使用训练数据预测测试数据(7 天的收盘价)
# 资源:http://machinelearningmastery.com/autoregression-models-time-series-forecasting-python/
from statsmodels.tsa.ar_model import AutoReg as AR  # 导入自回归模型
from sklearn.metrics import mean_squared_error  # 导入均方误差计算函数

# 获取测试数据和训练数据的关闭价
test = test['Close'].values
train_pr = train['Close'].values

# 训练并拟合自回归模型
model = AR(train_pr, lags=1)  # 创建自回归模型,滞后为 1
model_fit = model.fit()  # 拟合模型
print("Lag: %s" % model_fit.ar_lags)  # 打印模型的滞后值
print("Coefficients: %s" % model_fit.params)  # 打印模型的系数

# 进行预测
pred = model_fit.predict(start=len(train), end=len(train_pr) + len(test) - 1, dynamic=False)  # 从训练数据的末尾开始预测
mse = mean_squared_error(test, pred)  # 计算均方误差
print("Test MSE {0:.3f}".format(mse))  # 打印测试均方误差

# 绘制测试值和预测值
plt.plot(test, label='true value')  # 绘制测试值,标签为真实值
plt.plot(pred, color='red', label='prediction')  # 绘制预测值,颜色为红色,标签为预测值
plt.title("Autoregressive model")  # 设置图表标题
plt.legend()  # 设置图例

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

代码总结

  1. 导入库:导入 matplotlib.pyplotnumpypandasseaborn 等库,并设置绘图样式。
  2. 读取数据:从指定路径读取训练数据和测试数据,并检查它们的形状。
  3. 数据预处理
    • 反转日期顺序:将数据按时间顺序排列。
    • 转换日期格式:定义一个函数将字符串日期转换为 datetime 对象,并应用到训练数据的日期列。
    • 设置日期为索引:将日期列设置为 DataFrame 的索引。
    • 检查缺失值:检查训练数据中是否有缺失值。
  4. 可视化
    • 关闭价的可视化:绘制原始数据和对数尺度的关闭价图表,展示了从 2016 年开始的上升趋势。
    • 降低采样频率:绘制前一年的平均价格和年末价格的图表,分析数据的长期趋势。
  5. 投资回报率(ROI)
    • 计算 ROI:计算每天的 ROI,并绘制图表。
  6. 移动平均
    • SMA 和 EMA:计算简单移动平均(SMA)和指数移动平均(EMA),并绘制图表。
    • 非恒定方差:通过滚动平均和标准差确认数据中的非恒定方差。
  7. 滞后图和自相关性
    • 滞后图:绘制滞后图,检查数据是否随机。
    • 自相关图:绘制自相关图,量化数据点之间的相关性。
    • 部分自相关图:绘制部分自相关图,确定自回归模型的阶数。
  8. 自回归模型
    • 训练和预测:使用自回归模型 fitting 训练数据,并预测测试数据的关闭价,计算均方误差。
    • 绘制预测结果:可视化测试值和预测值,展示自回归模型的性能。
posted @   爱上编程技术  阅读(2)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· DeepSeek “源神”启动!「GitHub 热点速览」
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 我与微信审核的“相爱相杀”看个人小程序副业
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· spring官宣接入deepseek,真的太香了~
点击右上角即可分享
微信分享提示