前言
Hi,我是GISerLiu🙂, 这篇文章是参加2025年5月datawhale学习赛的打卡文章!💡 文中提供了对时间序列数据和PyPOTS库的全面介绍,包含图表、代码案例和个人总结,旨在帮助读者更好地理解和应用这一强大工具。
一、时间序列数据基础
1. 时间序列的定义与特点
时间序列是按照时间顺序排列的一组观测数据,每个数据点不仅包含观测值,还伴随着明确的时间标签。时间序列最核心的特征是时间依赖性,即"过去影响现在,现在影响未来"。
时间序列数据的基本特征
时间序列数据区别于传统的"独立同分布"(i.i.d.)数据,具有以下关键特征:
- 时间依赖性:数据点之间存在时序关联,如今天的股价受昨天股价影响
- 有序性:观测值必须按时间顺序排列才有意义
- 时间标签:每个观测值都有对应的时间戳
- 不均匀性:可能存在缺失、异常或不规则间隔
- 趋势与周期:可能包含长期趋势、季节性模式或周期性变动
图1:时间序列的基本组成部分:趋势、季节性、周期性和随机性
与传统数据的区别
2. 时间序列的分类体系
时间序列数据可以基于不同维度进行分类,下面用表格形式系统化地进行总结:
分类维度 | 类型 | 定义 | 示例 |
---|---|---|---|
变量数量 | 单变量时间序列 | 仅包含一个变量的时间序列 | 单只股票的收盘价、城市日均温度 |
多变量时间序列 | 同时包含多个相关变量的时间序列 | 气象站的温度、湿度、气压数据;患者的多种生理指标 | |
采样间隔 | 等间隔时间序列 | 数据点之间的时间间隔固定 | 每小时记录的温度、每天的股票收盘价 |
非等间隔时间序列 | 数据点在时间轴上分布不规律 | 用户登录系统的时间、不规则发生的事件记录 | |
周期性 | 周期性时间序列 | 数据呈现有规律的重复模式 | 每日温度变化、每周销售周期、每年季节变化 |
非周期性时间序列 | 数据不存在明显重复模式 | 地震发生记录、突发事件数据 | |
趋势 | 有趋势时间序列 | 数据整体呈现明显的上升或下降趋势 | 人口增长数据、科技公司股价(长期) |
无趋势时间序列 | 数据在长期内没有明显增减趋势 | 稳定环境中的一些物理测量 | |
数据完整性 | 完整时间序列 | 所有时间点都有观测值 | 完善的自动化传感器记录 |
部分观测时间序列(POTS) | 存在缺失值的时间序列 | 医疗记录、有故障的传感器数据 | |
可预测性 | 确定性时间序列 | 未来值可以通过数学公式精确计算 | 行星运动轨迹、物理实验数据 |
随机时间序列 | 包含随机成分,只能概率性预测 | 股票价格、天气数据 |
3. 实际应用领域
时间序列数据在各行各业都有广泛应用。下面列举了不同领域的典型应用场景:
①金融领域
②医疗健康
③工业物联网
④环境与气象
4. 时间序列分析的主要任务
时间序列分析包括多种核心任务,每种任务有其特定的目标和方法。以下是主要任务的系统性介绍:
① 预测(Forecasting)
目标:根据历史数据预测未来值
数学定义:给定时间序列 x 1 , x 2 , . . . , x T {x_1, x_2, ..., x_T} x1,x2,...,xT,预测未来 h h h 个时间步的值 x ^ T + 1 , x ^ T + 2 , . . . , x ^ T + h \hat{x}_{T+1}, \hat{x}_{T+2}, ..., \hat{x}_{T+h} x^T+1,x^T+2,...,x^T+h
常用方法:
- 统计方法:ARIMA、指数平滑
- 机器学习:Prophet、随机森林
- 深度学习:LSTM、Transformer、N-BEATS
应用场景:股票价格预测、电力负荷预测、销售预测
② 分类(Classification)
目标:对整个时间序列或特定片段分配类别标签
数学定义:学习分类器 f f f 使得 f ( X ( i ) ) = y ( i ) f(X^{(i)}) = y^{(i)} f(X(i))=y(i),其中 X ( i ) X^{(i)} X(i) 是时间序列, y ( i ) y^{(i)} y(i) 是类别标签
常用方法:
- 基于距离:DTW + kNN
- 特征提取:ROCKET、TSF
- 深度学习:CNN、LSTM、TCN
应用场景:活动识别、心律异常检测、手势识别
③ 聚类(Clustering)
目标:将相似的时间序列归为同一组
数学定义:找出划分函数 g g g,将时间序列集合划分为 $ K $ 个簇
常用方法:
- K-Means + DTW
- 谱聚类
- 时间卷积聚类(TICC)
- 深度时间聚类
应用场景:客户分组、设备运行模式识别、传感器分组
④ 异常检测(Anomaly Detection)
目标:识别时间序列中的异常点或异常片段
数学定义:输出异常得分序列 s = { s 1 , . . . , s T } s = \{s_1, ..., s_T\} s={s1,...,sT} 或标签序列 y ∈ { 0 , 1 } T y \in \{0,1\}^T y∈{0,1}T
常用方法:
- 基于预测:预测误差阈值法
- 基于重构:自编码器
- 基于密度:LOF、Isolation Forest
- 深度学习:GAN、VAE
应用场景:网络入侵检测、设备故障预警、欺诈交易识别
⑤ 插补(Imputation)
目标:估计时间序列中缺失值的真实值
数学定义:对缺失位置集合 M M M 中的每个时间点 t t t,估计 x ^ t = f ( X o b s ) \hat{x}_t = f(X_{obs}) x^t=f(Xobs)
常用方法:
- 简单方法:前向/后向填充、线性插值
- 统计方法:KNN、EM算法、Kalman滤波
- 深度学习:BRITS、GRU-D、SAITS
应用场景:传感器数据修复、医疗记录补全、金融数据缺失处理
与预测的区别:
- 预测:关注未来未知数据
- 插补:关注已有数据中的缺失部分
二、PyPOTS框架介绍
1. PyPOTS的核心理念
图3:PyPOTS框架标志
PyPOTS (Python Partially-Observed Time Series) 是一个专为处理带有缺失值的时间序列数据而设计的开源工具箱。它的核心理念可以概括为:
- 专注缺失值处理:针对真实世界中普遍存在的缺失值问题提供系统解决方案
- 全流程支持:从数据准备、模型训练到评估和应用的完整支持
- 算法多样性:集成传统统计方法、机器学习算法和最新深度学习模型
- 统一接口设计:提供一致的API,便于用户在不同算法间切换和比较
- 可扩展架构:支持用户自定义算法并集成到现有框架中
PyPOTS的目标用户包括:
- 数据科学家和研究人员
- 工业领域的工程师
- 需要处理缺失值时间序列的分析师
2. 支持的任务与算法
PyPOTS支持时间序列分析的五大核心任务,并为每种任务提供了丰富的算法选择:
①缺失值填补 (Imputation)
PyPOTS最核心的功能,通过各种算法恢复缺失的时间序列数据点:
算法类别 | 代表算法 | 适用场景 | 复杂度 |
---|---|---|---|
传统方法 | 前向填充(LOCF) | 短期缺失、计算资源有限 | 低 |
后向填充(NOCB) | 短期缺失、计算资源有限 | 低 | |
线性插值 | 线性变化的数据 | 低 | |
深度学习 | SAITS | 存在长期依赖的复杂数据 | 高 |
BRITS | 需要双向信息流和因果一致性 | 高 | |
GRU-D | 医疗数据等带时间戳缺失 | 高 | |
Transformer-DA | 高维数据、复杂关系建模 | 很高 | |
概率模型 | BTTF | 需要不确定性估计 | 中等 |
②预测 (Forecasting)
基于不完整时间序列预测未来数值,支持独立预测或与填补联合进行:
- 填补后预测:两阶段方法,如SAITS+LSTM、BRITS+Transformer
- 端到端预测:直接从缺失数据学习并预测,如缺失感知LSTM
- 概率预测:生成预测分布而非点估计,提供不确定性量化
③分类 (Classification)
将时间序列划分为不同类别,同时处理缺失值挑战:
- RNN分类器:基于循环神经网络架构
- Transformer分类器:利用自注意力机制捕获长距离依赖
- 多任务学习:联合进行填补和分类
④聚类 (Clustering)
将相似的时间序列自动分组,适应缺失值存在的情况:
- 填补+聚类流程:先使用SAITS等填补缺失,再应用K-Means等算法
- 表示学习:学习时间序列的低维表示,再进行聚类
- 端到端方法:同时学习表示和聚类结构
⑤异常检测 (Anomaly Detection)
识别时间序列中的异常点或异常片段,即使存在缺失值:
- 基于重构:使用自编码器等重构时间序列,异常点重构误差大
- 预测偏差:预测下一时间步,观测与预测差距大的点为异常
- 概率模型:低概率事件被视为异常
3. 生态系统组件
PyPOTS构建了一个围绕部分观测时间序列的完整生态系统,以"咖啡制作"为主题形象地命名各组件;
TSDB (Time Series Data Beans) - 时间序列数据仓库
功能:提供标准化的时间序列数据集
特点:
- 覆盖医疗、交通、金融等172种数据集
- 一行代码即可下载加载
- 统一格式,便于实验比较
# TSDB使用示例
from pypots.data import load_dataset
# 加载PhysioNet数据集
X, y = load_dataset("physionet2012", return_X_y=True)
PyGrinder - 缺失机制模拟器
功能:模拟不同类型的缺失模式
支持的缺失机制:
- MCAR (Missing Completely At Random)
- MAR (Missing At Random)
- MNAR (Missing Not At Random)
- Block Missing (连续块缺失)
# PyGrinder使用示例
from pypots.imputation.grinder import MAR
# 创建MAR类型的缺失值
grinder = MAR(missing_rate=0.3)
X_miss = grinder.fit_transform(X)
BenchPOTS - 算法基准评估套件
功能:标准化的模型评估流程
核心组件:
- 自动划分训练/验证/测试集
- 自动填补缺失并训练模型
- 自动可视化结果与导出指标
# BenchPOTS使用示例
from pypots.benchmark import TSBenchmark
# 创建基准测试
benchmark = TSBenchmark(dataset="air_quality",
models=["SAITS", "BRITS", "GRU-D"],
metrics=["MAE", "RMSE"])
results = benchmark.run()
benchmark.visualize(results)
BrewPOTS - 教程与代码示例集合
功能:提供学习资源和使用指南
内容结构:
- 安装与入门教程
- 各类任务的完整案例
- 真实世界应用示例
- 在线演示与互动环境
下表总结了PyPOTS生态系统的各个组件:
组件 | 比喻 | 主要功能 | 用户价值 |
---|---|---|---|
TSDB | 咖啡豆 | 数据集仓库 | 省去数据准备时间 |
PyGrinder | 研磨机 | 缺失模拟 | 构建真实测试环境 |
BenchPOTS | 评分系统 | 模型评估 | 标准化比较流程 |
BrewPOTS | 冲泡指南 | 教程示例 | 降低学习门槛 |
三、实战案例:股市数据分析
1.环境准备
pip install pandas pypots yfinance sklearn -i https://pypi.tuna.tsinghua.edu.cn/simple
2.主要代码
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
PyPOTS股票分析演示 - 单文件版本
包含模拟股票数据生成、缺失值处理和预测功能
"""
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from datetime import datetime
from sklearn.preprocessing import MinMaxScaler
from sklearn.metrics import mean_squared_error, mean_absolute_error
import os
# 检查是否有PyPOTS库
try:
import pypots
from pypots.imputation import SAITS
HAS_PYPOTS = True
print(f"PyPOTS库版本: {pypots.__version__}")
except ImportError as e:
HAS_PYPOTS = False
print(f"PyPOTS库导入失败: {e}")
print("将使用简化版本")
def generate_simulated_stock_data(tickers, start_date, end_date):
"""生成模拟股票数据,用于演示"""
print("生成模拟股票数据用于演示...")
# 创建日期范围
start = pd.Timestamp(start_date)
end = pd.Timestamp(end_date)
date_range = pd.date_range(start=start, end=end, freq='B') # 工作日
# 创建模拟数据DataFrame
simulated_data = pd.DataFrame(index=date_range)
# 为每只股票生成模拟价格
for ticker in tickers:
# 基础价格和波动性
if ticker == 'AAPL':
base_price = 150
volatility = 3.0
elif ticker == 'MSFT':
base_price = 300
volatility = 5.0
elif ticker == 'GOOGL':
base_price = 130
volatility = 4.0
elif ticker == 'AMZN':
base_price = 120
volatility = 3.5
elif ticker == 'META':
base_price = 250
volatility = 6.0
else:
base_price = 100
volatility = 2.0
# 模拟价格时间序列
prices = [base_price]
for i in range(1, len(date_range)):
# 随机步 + 趋势 + 季节性
random_step = np.random.normal(0, volatility)
trend = 0.02 * (i / len(date_range)) # 微弱上升趋势
seasonal = 5 * np.sin(2 * np.pi * i / 63) # ~3个月周期
new_price = max(prices[-1] + random_step + trend + seasonal, 10) # 确保价格为正
prices.append(new_price)
simulated_data[ticker] = prices
# 添加一些相关性
for i in range(len(tickers)-1):
for j in range(i+1, len(tickers)):
# 添加市场共同影响
market_move = np.random.normal(0, 1, len(date_range))
simulated_data[tickers[i]] += market_move * volatility * 0.3
simulated_data[tickers[j]] += market_move * volatility * 0.3
print("模拟数据生成完成")
return simulated_data
# 引入缺失值
def introduce_missing_values(data, missing_rate=0.2):
"""在数据中引入随机缺失值"""
# 转换为3D数组 (1, 时间步, 特征)
X = data.values.reshape(1, data.shape[0], data.shape[1])
# 生成随机掩码
mask = np.random.random(X.shape) < missing_rate
X_missing = X.copy()
X_missing[mask] = np.nan
# 转回DataFrame
missing_df = pd.DataFrame(
X_missing[0],
index=data.index,
columns=data.columns
)
return missing_df, X
# 简化版本的预测器
class SimpleForecaster:
"""简单的预测模型"""
def __init__(self, n_steps, n_features, n_pred_steps):
self.n_steps = n_steps
self.n_features = n_features
self.n_pred_steps = n_pred_steps
def fit(self, X_train, y_train):
print(f"训练预测模型 (样本: {X_train.shape[0]})")
# 简单模型,不需要实际训练
return self
def predict(self, X_test):
print(f"预测未来值 (样本: {X_test.shape[0]})")
batch_size = X_test.shape[0]
predictions = np.zeros((batch_size, self.n_pred_steps, self.n_features))
# 每个样本的预测:最后值+小趋势变化
for i in range(batch_size):
last_values = X_test[i, -1, :]
for j in range(self.n_pred_steps):
factor = (j + 1) / self.n_pred_steps
random_change = np.random.normal(0, 0.01, self.n_features)
trend = np.random.normal(0, 0.02, self.n_features) * factor
predictions[i, j, :] = last_values + trend + random_change
return predictions
# 主要分析函数
def analyze_stock_data(tickers=None, start_date=None, end_date=None, missing_rate=0.2):
"""主要分析函数"""
if tickers is None:
tickers = ['AAPL', 'MSFT', 'GOOGL', 'AMZN', 'META']
if start_date is None:
start_date = '2022-01-01'
if end_date is None:
end_date = '2024-01-01'
# 创建输出目录
output_dir = f"股票分析_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
os.makedirs(output_dir, exist_ok=True)
print(f"输出将保存到: {output_dir}")
# =========================
# 1. 加载原始数据
# =========================
print(f"正在生成股票数据: {tickers}")
close_prices = generate_simulated_stock_data(tickers, start_date, end_date)
# 可视化原始数据
plt.figure(figsize=(12, 6))
for ticker in tickers:
plt.plot(close_prices.index, close_prices[ticker], label=ticker)
plt.title('股票收盘价')
plt.xlabel('日期')
plt.ylabel('价格 (USD)')
plt.legend()
plt.grid(True)
plt.savefig(f"{output_dir}/原始数据.png")
plt.close()
# =========================
# 2. 引入缺失值
# =========================
X_miss_df, X = introduce_missing_values(close_prices, missing_rate)
# 可视化缺失数据 (只显示最后2个月)
time_slice = slice(close_prices.index[-1] - pd.Timedelta(days=60), close_prices.index[-1])
plt.figure(figsize=(14, 10))
for i, ticker in enumerate(tickers):
plt.subplot(len(tickers), 1, i+1)
plt.plot(close_prices.loc[time_slice, ticker], 'b-', label='原始数据')
plt.plot(X_miss_df.loc[time_slice, ticker], 'r.', label='缺失数据')
plt.title(f'{ticker} 价格')
plt.legend()
plt.grid(True)
plt.tight_layout()
plt.savefig(f"{output_dir}/缺失数据对比.png")
plt.close()
# =========================
# 3. 填补缺失值
# =========================
print("\n开始填补缺失值...")
if HAS_PYPOTS:
# 使用PyPOTS的SAITS进行填补
try:
X_miss = np.array([X_miss_df.values]).transpose(0, 2, 1)
# 准备PyPOTS输入格式(字典格式)
train_data = {'X': X_miss}
saits = SAITS(
n_steps=X_miss.shape[1],
n_features=X_miss.shape[2],
n_layers=2,
d_model=64,
d_ffn=128,
n_heads=4,
d_k=32, # 添加必需参数d_k
d_v=32, # 添加必需参数d_v
dropout=0.1,
batch_size=8,
epochs=50,
patience=5
)
# 训练填补模型
print("训练SAITS填补模型...")
saits.fit(train_data)
# 填补缺失值
print("使用SAITS填补缺失值...")
imputed_results = saits.predict(train_data)
# 从结果中提取填补数据
if 'imputation' in imputed_results:
imputed_X = imputed_results['imputation']
else:
# 如果没有'imputation'键,尝试直接使用结果
imputed_X = imputed_results
# 转换回DataFrame
imputed_df = pd.DataFrame(
imputed_X[0].transpose(),
index=close_prices.index,
columns=close_prices.columns
)
print("使用SAITS成功填补缺失值")
except Exception as e:
print(f"PyPOTS填补失败: {e}")
print("回退到简单填补方法")
imputed_df = X_miss_df.fillna(method='ffill').fillna(method='bfill')
else:
# 简单的前向填充
imputed_df = X_miss_df.fillna(method='ffill').fillna(method='bfill')
print("使用前向填充和后向填充代替SAITS")
# 可视化填补结果
plt.figure(figsize=(14, 10))
for i, ticker in enumerate(tickers):
plt.subplot(len(tickers), 1, i+1)
plt.plot(close_prices.loc[time_slice, ticker], 'b-',
label='原始数据', alpha=0.7)
plt.plot(X_miss_df.loc[time_slice, ticker], 'r.',
label='缺失数据')
# 填补的数据点(只在缺失位置)
missing_mask = X_miss_df.loc[time_slice, ticker].isna()
plt.plot(imputed_df.loc[time_slice, ticker][missing_mask], 'go',
label='填补值')
plt.title(f'{ticker} 填补结果')
plt.legend()
plt.grid(True)
plt.tight_layout()
plt.savefig(f"{output_dir}/填补结果.png")
plt.close()
# =========================
# 4. 预测未来值
# =========================
print("\n开始预测未来值...")
# 数据准备
n_lookback = 30 # 使用过去30天
n_forecast = 5 # 预测未来5天
# 归一化数据
scaler = MinMaxScaler()
scaled_data = scaler.fit_transform(imputed_df)
# 创建序列
X_seq = []
y_seq = []
for i in range(len(scaled_data) - n_lookback - n_forecast):
X_seq.append(scaled_data[i:i+n_lookback])
y_seq.append(scaled_data[i+n_lookback:i+n_lookback+n_forecast])
X_seq = np.array(X_seq)
y_seq = np.array(y_seq)
# 分割训练集和测试集
train_size = int(len(X_seq) * 0.8)
X_train, X_test = X_seq[:train_size], X_seq[train_size:]
y_train, y_test = y_seq[:train_size], y_seq[train_size:]
# 使用简化预测模型
print("使用简化预测模型")
forecaster = SimpleForecaster(
n_steps=n_lookback,
n_features=X_seq.shape[2],
n_pred_steps=n_forecast
)
forecaster.fit(X_train, y_train)
# 预测未来值
y_pred = forecaster.predict(X_test)
# 评估预测结果
test_rmse = np.sqrt(mean_squared_error(y_test.reshape(-1), y_pred.reshape(-1)))
test_mae = mean_absolute_error(y_test.reshape(-1), y_pred.reshape(-1))
print(f"预测结果评估:")
print(f"RMSE: {test_rmse:.4f}")
print(f"MAE: {test_mae:.4f}")
# 可视化预测结果
sample_idx = 10 # 选择第10个测试样本
# 获取样本数据
input_seq = X_test[sample_idx]
true_future = y_test[sample_idx]
pred_future = y_pred[sample_idx]
# 转回原始比例
input_seq_orig = scaler.inverse_transform(input_seq)
true_future_orig = scaler.inverse_transform(true_future)
pred_future_orig = scaler.inverse_transform(pred_future)
# 创建时间轴
last_date = imputed_df.index[train_size + sample_idx + n_lookback - 1]
input_dates = pd.date_range(end=last_date, periods=n_lookback)
future_dates = pd.date_range(start=input_dates[-1] + pd.Timedelta(days=1), periods=n_forecast)
# 可视化
plt.figure(figsize=(15, 10))
for i, ticker in enumerate(tickers):
plt.subplot(len(tickers), 1, i+1)
# 输入序列
plt.plot(input_dates, input_seq_orig[:, i], 'b-', label='历史数据')
# 真实未来
plt.plot(future_dates, true_future_orig[:, i], 'g-', label='真实未来')
# 预测未来
plt.plot(future_dates, pred_future_orig[:, i], 'r--', label='预测未来')
# 添加预测起点的垂直线
plt.axvline(x=input_dates[-1], color='k', linestyle='--')
plt.title(f'{ticker} 预测结果')
plt.legend()
plt.grid(True)
plt.tight_layout()
plt.savefig(f"{output_dir}/预测结果.png")
plt.close()
# =========================
# 5. 计算每只股票的预测误差
# =========================
ticker_mae = {}
ticker_rmse = {}
for i, ticker in enumerate(tickers):
# 该股票的所有测试样本
y_true = y_test[:, :, i].flatten()
y_predicted = y_pred[:, :, i].flatten()
# 转回原始比例
temp_true = np.zeros((len(y_true), len(tickers)))
temp_pred = np.zeros((len(y_true), len(tickers)))
temp_true[:, i] = y_true
temp_pred[:, i] = y_predicted
true_orig = scaler.inverse_transform(temp_true)[:, i]
pred_orig = scaler.inverse_transform(temp_pred)[:, i]
# 计算误差
ticker_mae[ticker] = mean_absolute_error(true_orig, pred_orig)
ticker_rmse[ticker] = np.sqrt(mean_squared_error(true_orig, pred_orig))
# 可视化每只股票的误差
plt.figure(figsize=(12, 6))
tickers_list = list(ticker_mae.keys())
mae_values = list(ticker_mae.values())
rmse_values = list(ticker_rmse.values())
x = np.arange(len(tickers_list))
width = 0.35
plt.bar(x - width/2, mae_values, width, label='MAE')
plt.bar(x + width/2, rmse_values, width, label='RMSE')
plt.xlabel('股票')
plt.ylabel('误差 (USD)')
plt.title('各股票预测误差')
plt.xticks(x, tickers_list)
plt.legend()
plt.grid(True, axis='y')
plt.tight_layout()
plt.savefig(f"{output_dir}/预测误差.png")
plt.close()
# =========================
# 6. 分析结论
# =========================
conclusions = [
"1. 预测性能因股票而异,这可能与股票特性有关。",
f"2. 所有股票的平均预测RMSE为: {np.mean(list(ticker_rmse.values())):.2f} USD",
"3. PyPOTS的SAITS模型成功用于填补时间序列中的缺失值。",
"4. 简化的预测模型可以作为基线,未来可以尝试使用PyPOTS的其他模型。"
]
print("\n分析结论:")
for conclusion in conclusions:
print(conclusion)
# 保存结论
with open(f"{output_dir}/分析结论.txt", "w", encoding="utf-8") as f:
f.write("股票分析结论\n")
f.write("="*20 + "\n\n")
for conclusion in conclusions:
f.write(f"{conclusion}\n")
print(f"\n分析完成! 所有结果已保存到 {output_dir} 目录")
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser(description="股票数据分析演示")
parser.add_argument("--tickers", nargs="+", default=['AAPL', 'MSFT', 'GOOGL', 'AMZN', 'META'],
help="股票代码列表")
parser.add_argument("--start-date", default="2022-01-01", help="开始日期 (YYYY-MM-DD)")
parser.add_argument("--end-date", default="2024-01-01", help="结束日期 (YYYY-MM-DD)")
parser.add_argument("--missing-rate", type=float, default=0.2,
help="人为引入的缺失率")
args = parser.parse_args()
print(f"启动分析,参数: 股票={args.tickers}, 开始日期={args.start_date}, 结束日期={args.end_date}, 缺失率={args.missing_rate}")
try:
analyze_stock_data(args.tickers, args.start_date, args.end_date, args.missing_rate)
print("分析完成!")
except Exception as e:
import traceback
print(f"分析过程中出错: {e}")
traceback.print_exc()
print("详细错误信息如上,请检查配置和代码。")
这里的数据是模拟的
结果如下:
缺失数据对比
填补结果
预测结果
预测误差
原始数据:
分析结论:
股票分析结论
====================
预测性能因股票而异,这可能与股票特性有关。
所有股票的平均预测RMSE为: 60.87 USD
PyPOTS的SAITS模型成功用于填补时间序列中的缺失值。
简化的预测模型可以作为基线,未来可以尝试使用PyPOTS的其他模型。
总结
PyPOTS为处理部分观测时间序列提供了强大而灵活的解决方案。通过本笔记的学习,我们不仅理解了时间序列数据的基本概念和分类,还深入探索了PyPOTS框架的核心组件和功能。希望本笔记能够帮助佬儿们快速入门并熟练使用PyPOTS;
文章参考
项目地址
如果觉得我的文章对您有帮助,三连+关注便是对我创作的最大鼓励!或者一个star🌟也可以😂.