Python 实战股票时间序列分析与预测:从数据可视化到双模型建模
前言
股票市场数据是典型的时间序列数据,价格、成交量、涨跌幅等指标随时间连续变化,背后暗藏市场波动规律。本文基于 Python 全套工具链,完成一份完整的股票数据分析项目:从数据读取、清洗预处理、多维度可视化探索,再到线性回归与ARIMA两大模型搭建、效果对比,最后实现未来短期股价预测。全程附核心代码、结果解读与踩坑总结,适合数据分析入门、金融量化初学者参考学习。
一、项目整体介绍
1.1 项目目标
依托股票历史交易数据,完成全流程时间序列分析:
- 探查数据质量,完成数据清洗与标准化预处理;
- 通过折线图、K 线图、柱状图、直方图可视化股价、均线、成交量、涨跌幅分布;
- 搭建线性回归、ARIMA 时间序列模型对收盘价进行预测;
- 对比两个模型预测效果,并基于最优模型预测未来 10 个交易日股价。
1.2 开发环境与数据集
- 开发工具:Python 3.x、Jupyter Notebook
- 核心依赖库:
pandas(数据处理)、numpy(数值计算)、matplotlib(可视化)、pyecharts(交互式 K 线图)、sklearn(机器学习模型)、statsmodels(ARIMA 时间序列模型) - 数据集:
股价数据.xlsx,共 611 条交易数据,包含日期、开盘价、收盘价、最高价、最低价、成交量、涨跌幅、5/10/20 日均线等 14 个字段,数据完整无缺失值。
二、阶段一:数据导入与基础探查
数据分析第一步永远是认识数据,我们先读取数据、查看基本信息、检查缺失值,判断数据是否可用。
2.1 导入库与全局配置
绘图前提前配置字体,解决 Matplotlib 中文乱码、负号显示异常问题:
python
运行
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# 全局设置:中文+负号正常显示
plt.rcParams["font.family"] = "SimHei"
plt.rcParams["axes.unicode_minus"] = False
2.2 读取数据并基础探查
python
运行
# 读取Excel数据
df = pd.read_excel("股价数据.xlsx")
# 查看前5行数据,确认加载成功
print("数据前5行:")
print(df.head())
# 查看数据类型、行数、字段数
print("\n数据基本信息:")
df.info()
# 统计全列缺失值(判断数据质量)
print("\n各字段缺失值统计:")
print(df.isnull().sum())
2.3 结果解读
- 数据集共611 行 14 列,
date为文本类型,其余 13 个字段均为浮点型; - 全字段缺失值均为 0,数据完整性良好,无需做缺失值填充;
- 原始数据日期为倒序排列(最新日期在前),后续需要按时间正序重排。
三、阶段二:数据预处理与特征筛选
原始股票数据存在时间格式不规范、顺序颠倒、冗余字段过多问题,必须预处理后才能用于时间序列分析。
3.1 核心预处理代码
python
运行
# 1. 将日期列转为标准datetime时间格式(时间序列必备)
df['date'] = pd.to_datetime(df['date'])
# 2. 按时间从早到晚升序排序,修正原始倒序问题
df.sort_values(by='date', inplace=True)
# 3. 保留核心分析字段,剔除冗余字段
df = df[['date', 'open', 'close', 'high', 'low',
'volume', 'p_change', 'ma5', 'ma10', 'ma20']]
# 4. 重置索引,保证数据行连续整洁
df.reset_index(drop=True, inplace=True)
# 查看预处理后数据
print(df.head())
3.2 预处理说明
- 时间格式转换:
pd.to_datetime是时间序列分析的基础,后续绘图、建模均依赖标准时间格式; - 时间排序:股票时间序列要求数据按时间递增排列,否则会破坏时序逻辑,导致模型失效;
- 特征筛选:剔除
price_change、v_ma5等冗余字段,仅保留股价、成交量、涨跌幅、均线等核心指标,降低计算开销。
四、阶段三:探索性数据分析(EDA)+ 可视化
可视化是挖掘数据规律最直观的方式,本项目完成四类经典金融图表绘制,全方位解读股票走势。
4.1 收盘价与均线走势折线图
均线(MA)是股票技术分析核心指标,5/10/20 日均线可以判断短期、中期股价趋势、金叉 / 死叉信号。
python
运行
plt.figure(figsize=(14, 6))
# 绘制收盘价实线
plt.plot(df['date'], df['close'], label='收盘价')
# 绘制三条均线(虚线区分)
plt.plot(df['date'], df['ma5'], label='5日均线', linestyle='--')
plt.plot(df['date'], df['ma10'], label='10日均线', linestyle='--')
plt.plot(df['date'], df['ma20'], label='20日均线', linestyle='--')
plt.legend()
plt.title('收盘价与均线走势图')
plt.grid(alpha=0.3)
plt.show()
解读:收盘价紧贴均线波动,整体走势平稳,短期均线与中长期均线交叉频繁,反映股价存在阶段性震荡。
4.2 交互式 K 线图(pyecharts)
K 线图直观展示每日开盘、收盘、最高、最低价格,结合交互工具可缩放、查看单日详情。
python
运行
from pyecharts.charts import Kline
from pyecharts import options as opts
# 组装K线四要素:开盘、收盘、最高、最低
kline_data = df[['open', 'close', 'high', 'low']].values.tolist()
kline = (
Kline()
.add_xaxis(df['date'].dt.strftime('%Y-%m-%d').tolist())
.add_yaxis("股票K线图", kline_data)
.set_global_opts(
title_opts=opts.TitleOpts(title="股票K线走势图"),
toolbox_opts=opts.ToolboxOpts(is_show=True) # 开启工具箱:下载、缩放、数据查看
)
)
# Jupyter中直接展示图表,普通py文件使用 kline.render("kline.html")
kline.render_notebook()
4.3 成交量柱状图
成交量反映市场交易活跃度,是判断股价涨跌动能的重要依据。
python
运行
plt.figure(figsize=(14, 6))
plt.bar(df['date'], df['volume'])
plt.title('股票成交量柱状图')
plt.xlabel('日期')
plt.ylabel('成交量')
plt.xticks(rotation=45) # 日期旋转,避免重叠
plt.show()
解读:大部分交易日成交量处于中等水平,少数交易日出现放量(柱子骤增),对应股价短期大幅波动。
4.4 涨跌幅分布直方图
统计每日涨跌幅分布,判断股票整体波动特征。
python
运行
plt.figure(figsize=(14, 6))
# 绘制涨跌幅直方图,划分40个区间
plt.hist(df['p_change'], bins=40, alpha=0.7)
# 绘制红色虚线:涨跌分界线(0轴)
plt.axvline(0, color='red', linestyle='--', label='涨跌分界线')
plt.title('股票涨跌幅分布直方图')
plt.xlabel('涨跌幅(%)')
plt.ylabel('交易日数量')
plt.legend()
plt.grid(alpha=0.3, axis='y')
plt.show()
解读:涨跌幅近似正态分布,绝大多数交易日涨跌幅集中在 0 附近,极端大涨 / 大跌天数较少,说明该股票整体波动偏温和。
五、阶段四:构建时序数据集(建模前置准备)
时间序列预测需将原始数据转为监督学习格式:用历史特征预测当日收盘价,并划分训练集、测试集。
5.1 构造滞后特征 + 数据集划分
python
运行
# 构造滞后特征:前一日收盘价(金融时序经典特征)
df["close_lag1"] = df["close"].shift(1)
# shift会产生空值,删除空行
df = df.dropna()
# 划分数据集:前80%为训练集,后20%为测试集(时序数据禁止随机划分)
split_num = int(len(df) * 0.8)
train = df.iloc[:split_num]
test = df.iloc[split_num:]
# 定义特征列与预测标签
feature_cols = ["close_lag1", "open", "ma5"] # 特征:前一日收盘价、开盘价、5日均线
X_train = train[feature_cols]
y_train = train["close"] # 标签:当日收盘价
X_test = test[feature_cols]
y_test = test["close"]
print(f"训练集数据量:{len(train)} 条")
print(f"测试集数据量:{len(test)} 条")
重点提醒:时间序列数据绝对不能随机划分训练集 / 测试集,必须按时间顺序切割,模拟 “用历史预测未来” 的真实场景。
六、阶段五:模型一 线性回归预测
线性回归是入门级回归模型,运算简单、可解释性强,适合作为基准模型。
6.1 模型训练、预测与评估
python
运行
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score
# 定义模型评估函数(统一计算MAE、RMSE、R²)
def eval_model(y_true, y_pred):
mae = mean_absolute_error(y_true, y_pred)
rmse = np.sqrt(mean_squared_error(y_true, y_pred))
r2 = r2_score(y_true, y_pred)
print(f"平均绝对误差MAE:{mae:.2f}")
print(f"均方根误差RMSE:{rmse:.2f}")
print(f"拟合优度R²:{r2:.2f}")
# 训练线性回归模型
lr = LinearRegression()
lr.fit(X_train, y_train)
# 测试集预测
y_pred_lr = lr.predict(X_test)
# 模型评估
print("===== 线性回归模型评估结果 =====")
eval_model(y_test, y_pred_lr)
# 可视化:真实值 vs 预测值
plt.figure(figsize=(14, 6))
plt.plot(test["date"], y_test, label="真实收盘价", linewidth=2)
plt.plot(test["date"], y_pred_lr, label="线性回归预测值", linestyle="--")
plt.title("线性回归股价预测结果")
plt.xlabel("日期")
plt.ylabel("收盘价")
plt.legend()
plt.grid(alpha=0.3)
plt.show()
6.2 模型结果
- MAE(平均绝对误差):0.16
- RMSE(均方根误差):0.21
- R²(拟合优度):0.98
解读:R² 接近 1,说明线性回归模型拟合效果极佳,预测值与真实股价偏差很小。
七、阶段六:模型二 ARIMA 时间序列模型
ARIMA 是经典专业时间序列模型,专门处理时序数据的趋势、周期性,在金融预测中应用广泛。本项目采用滚动一步预测(工业界主流用法)。
7.1 ARIMA 模型训练与预测
python
运行
from statsmodels.tsa.arima.model import ARIMA
# 初始化历史数据与预测列表
history = list(train["close"])
predictions = []
# 滚动预测:逐个预测测试集每一日股价
for i in range(len(test)):
# 构建ARIMA模型,阶数 order=(10,1,0)
model = ARIMA(history, order=(10, 1, 0))
model_fit = model.fit()
# 预测下一日股价
yhat = model_fit.forecast()[0]
predictions.append(yhat)
# 将当日真实值加入历史数据,迭代更新模型
history.append(test["close"].iloc[i])
# 转为数组
y_pred_arima = np.array(predictions)
# 模型评估
print("\n===== ARIMA模型评估结果 =====")
eval_model(y_test, y_pred_arima)
# 可视化ARIMA预测效果
plt.figure(figsize=(14, 6))
plt.plot(test["date"], y_test, label="真实收盘价", linewidth=2)
plt.plot(test["date"], y_pred_arima, label="ARIMA预测值", linestyle="--", color="orange")
plt.title("ARIMA时间序列预测结果")
plt.xlabel("日期")
plt.ylabel("收盘价")
plt.legend()
plt.grid(alpha=0.3)
plt.show()
八、阶段七:双模型对比 + 未来 10 日股价预测
8.1 双模型效果同图对比
python
运行
plt.figure(figsize=(15, 6))
plt.plot(test["date"], y_test, label="真实收盘价", linewidth=2)
plt.plot(test["date"], y_pred_lr, label="线性回归", linestyle="--")
plt.plot(test["date"], y_pred_arima, label="ARIMA", linestyle="--", color="red")
plt.title("线性回归 & ARIMA 模型预测效果对比")
plt.legend()
plt.grid(alpha=0.3)
plt.show()
对比结论:两个模型均能精准跟随股价趋势,线性回归拟合略优,ARIMA 对小幅波动捕捉更细腻。
8.2 基于 ARIMA 预测未来 10 个交易日股价
选用 ARIMA 模型对全量数据训练,预测短期未来走势:
python
运行
# 全量收盘价数据训练模型
full_series = df["close"]
final_arima = ARIMA(full_series, order=(5, 1, 0)).fit()
# 预测未来10步(10个交易日)
future_pred = final_arima.get_forecast(steps=10).predicted_mean
# 输出预测结果
print("\n===== 未来10个交易日收盘价预测 =====")
for idx, price in enumerate(future_pred, 1):
print(f"第{idx}天预测收盘价:{price:.2f} 元")
预测结果摘要:未来 10 日股价整体在 12.25~12.42 元区间小幅震荡,无大幅涨跌趋势。
补充说明:代码运行出现
ValueWarning属于正常现象,原因是数据索引未指定时间频率,不影响预测结果。
九、项目总结与经验分享
9.1 项目整体复盘
- 数据层面:本次股票数据质量优秀,无缺失值、无明显异常值,仅需完成时间格式转换、排序、特征筛选即可投入使用;
- 可视化层面:折线图、K 线图、柱状图、直方图四大图表,分别从趋势、价格区间、交易活跃度、波动分布四个维度完成数据解读,覆盖金融分析基础场景;
- 模型层面:
- 线性回归:简单高效、拟合度高,适合快速建模、基准对比;
- ARIMA:专业时序模型,适配时间序列特性,滚动预测更贴合真实预测场景;
- 预测结论:该股票历史走势平稳,短期未来 10 个交易日以窄幅震荡为主,大涨大跌概率较低。
9.2 踩坑与避坑指南
- 时间序列数据禁止随机划分训练集和测试集,必须按时间顺序切割;
- Matplotlib 绘图务必提前配置中文字体,否则标题、图例出现乱码;
- 使用
shift()构造滞后特征后,必须删除空值,否则模型报错; - ARIMA 模型阶数
order(p,d,q)需要根据数据调试,不同股票数据最优阶数不同。
9.3 拓展方向(进阶学习)
- 引入 LSTM、Prophet 等深度学习 / 工业级时序模型,提升复杂行情预测精度;
- 新增 MACD、RSI、布林带等更多金融技术指标作为特征;
- 构建量价相关性分析、风险波动率分析,丰富分析维度;
- 结合多支股票数据,做板块联动分析。
十、写在最后
用 Python 做股票时间序列分析,是数据分析 + 金融知识结合的经典实战案例。本项目从基础的数据处理到模型落地,完整还原了企业中时序数据分析的工作流程。对于初学者而言,既能巩固pandas、可视化、机器学习基础,也能初步理解金融数据分析的逻辑。
⚠️ 温馨提示:本文所有分析、预测结果均基于历史模拟数据,仅用于技术学习与代码练习,不构成任何投资建议。股市有风险,投资需谨慎。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)