一、项目简介

本文利用Python对股票历史行情数据进行时间序列分析,完成数据可视化、描述性统计,并分别使用线性回归ARIMA 时间序列模型实现股价预测,对比两个模型效果,同时基于 ARIMA 完成未来 10 个交易日股价预测。

使用工具:pandasnumpymatplotlibpyechartsscikit-learnstatsmodels 数据集:股票 Excel 行情数据(包含日期、开盘价、收盘价、最高价、最低价、成交量、涨跌幅、5/10/20 日均线等字段)

二、环境准备

首先安装所需第三方库,本次使用 Anaconda 环境,执行如下命令:

python

运行

pip install pyecharts pandas numpy matplotlib scikit-learn statsmodels openpyxl

执行结果显示依赖库均已存在,无需重复安装。

三、数据导入与探索

3.1 导入依赖库并配置绘图环境

解决 Matplotlib 中文、负号显示异常问题:

python

运行

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

# 解决中文和负号显示问题
plt.rcParams["axes.unicode_minus"] = False
plt.rcParams["font.family"] = "SimHei"

3.2 读取数据与基础查看

读取 Excel 格式的股票数据,并查看前几行、数据整体信息、缺失值:

python

运行

# 读取股价数据
df = pd.read_excel("股价数据.xlsx")
# 查看前5行数据
print(df.head())

# 查看数据基本信息(字段、数据类型、样本量)
df.info()

# 统计各字段缺失值数量
print(df.isnull().sum())

数据说明: 数据集共611条样本、14个字段,包含日期、开盘价、收盘价、最高价、最低价、成交量、涨跌幅、5/10/20 日均线等,无缺失值,数据质量良好。

四、数据预处理

时间序列分析必须保证时间有序,同时精简分析字段:

python

运行

# 1. 将日期列转为时间格式
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())

五、股票数据可视化分析

5.1 收盘价与 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.title('收盘价与均线走势')
plt.legend()
plt.grid(alpha=0.3)
plt.show()

分析结论: 收盘价整体围绕均线波动,短期均线(5 日、10 日)贴合股价变化,20 日均线趋势更平缓,能反映中长期股价走势。

5.2 股票 K 线图(pyecharts)

使用pyecharts绘制交互式 K 线图,直观展示每日开盘、收盘、最高、最低价格:

python

运行

from pyecharts.charts import Kline
from pyecharts import options as opts
import webbrowser, os

# 提取K线所需数据:开盘、收盘、最高、最低
y_data = df[['open','close','high','low']].values.tolist()
x_data = df['date'].tolist()

# 构建K线图
kline = (
    Kline()
    .add_xaxis(x_data)
    .add_yaxis("股票K线", y_data)
    .set_global_opts(
        title_opts=opts.TitleOpts(title="股票行情K线图"),
        toolbox_opts=opts.ToolboxOpts(is_show=True)
    )
)

# 导出HTML并自动打开
html_name = "股票K线.html"
kline.render(html_name)
webbrowser.open("file://"+os.path.abspath(html_name))

运行后会在本地生成 HTML 文件,浏览器打开即可查看交互式 K 线图,支持缩放、数据查看、下载等功能。

5.3 成交量柱状图

成交量反映市场交易活跃度:

python

运行

plt.figure(figsize=(14,6))
plt.bar(df['date'],df['volume'])
plt.title('股票成交量柱状图')
plt.show()

5.4 涨跌幅分布直方图

统计单日涨跌幅分布,红色虚线为涨跌分界线:

python

运行

plt.figure(figsize=(14,6))
plt.hist(df['p_change'],bins=40)
plt.axvline(0, color='red',linestyle='--',label='涨跌分界线')
plt.legend()
plt.title('股票单日涨跌幅分布直方图')
plt.show()

分析结论: 股票单日涨跌幅主要集中在 0 值附近,小幅涨跌为常态,大幅涨跌样本数量较少。

六、构建数据集(特征工程 + 划分训练集 / 测试集)

时间序列采用滞后特征,使用前一日收盘价作为核心特征,结合开盘价、5 日均线预测当日收盘价:

python

运行

# 构造滞后1期特征:前一日收盘价
df["close_lag1"] = df["close"].shift(1)

# 去除因滞后产生的空值
df = df.dropna()

# 划分数据集:前80%训练集,后20%测试集
split = int(len(df)*0.8)
train = df.iloc[:split]
test = df.iloc[split:]

# 定义特征列与标签列
feature_cols = ["close_lag1", "open","ma5"]
X_train = train[feature_cols]
y_train = train["close"]
X_test = test[feature_cols]
y_test = test["close"]

print(f"训练集:{len(train)} 条 | 测试集:{len(test)} 条")

输出结果:训练集:488 条 | 测试集:122 条

七、模型一:线性回归股价预测

7.1 模型训练、预测与评估

使用平均绝对误差 (MAE)均方根误差 (RMSE)决定系数 (R²) 评估模型效果:

python

运行

from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score

# 定义模型评估函数
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"R2(拟合度):{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)

模型评估结果

plaintext

===== 线性回归模型评估 =====
MAE(平均绝对误差):0.16
RMSE(均方根误差):0.21
R2(拟合度):0.98

7.2 线性回归预测结果可视化

python

运行

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()

八、模型二:ARIMA 时间序列预测

ARIMA 是经典时间序列模型,本次采用滚动一步预测方式(工业界常用时序预测方案):

python

运行

from statsmodels.tsa.arima.model import ARIMA

# 初始化历史数据与预测列表
history = list(train["close"])
predictions = []

# 滚动单步预测
for i in range(len(test)):
    # 构建ARIMA模型,阶数 order=(5,1,1)
    model = ARIMA(history,order=(5,1,1))
    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)

模型评估结果

plaintext

===== ARIMA模型评估 =====
MAE(平均绝对误差):0.18
RMSE(均方根误差):0.26
R2(拟合度):0.97

8.1 ARIMA 预测结果可视化

python

运行

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()

九、双模型效果对比

将线性回归、ARIMA 预测结果与真实值同图对比,直观区分模型优劣:

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("线性回归 VS ARIMA 预测效果对比")
plt.legend()
plt.grid(alpha=0.3)
plt.show()

模型对比总结

  1. 两个模型拟合度均达到 0.97 以上,预测效果优秀;
  2. 线性回归 MAE、RMSE 更小,误差略低于 ARIMA;
  3. ARIMA 为纯时序模型,仅依赖历史股价,线性回归融合了开盘价、均线等特征,在本次任务中表现更优。

十、基于 ARIMA 预测未来 10 个交易日股价

使用全量数据训练 ARIMA 模型,预测未来 10 日收盘价:

python

运行

# 全量收盘价序列
full_series = df["close"]

# 训练ARIMA模型
final_arima = ARIMA(full_series,order=(5,1,0)).fit()

# 预测未来10步
future_pred = final_arima.get_forecast(steps=10).predicted_mean

# 输出预测结果
print("\n===== 未来10个交易日预测收盘价 =====")
for i,val in enumerate(future_pred,1):
    print(f"第{i}天预测股价:{val:.2f} 元")

预测输出结果

plaintext

===== 未来10个交易日预测收盘价 =====
第1天预测股价:12.25 元
第2天预测股价:12.31 元
第3天预测股价:12.28 元
第4天预测股价:12.36 元
第5天预测股价:12.42 元
第6天预测股价:12.40 元
第7天预测股价:12.41 元
第8天预测股价:12.41 元
第9天预测股价:12.40 元
第10天预测股价:12.39 元

提示:代码运行出现的ValueWarning为索引格式警告,不影响预测结果,可忽略。

十一、项目总结

  1. 数据层面:本次股票数据集完整无缺失,通过时间排序、特征构造完成时序数据预处理,满足建模要求;
  2. 可视化层面:完成均线、K 线、成交量、涨跌幅多维度可视化,清晰还原股票行情规律;
  3. 模型层面
    • 线性回归结合多特征,预测误差更小,适合该场景下的股价短期预测;
    • ARIMA 经典时序模型,仅依靠历史序列也能实现高精度预测,通用性更强;
  4. 业务层面:模型可实现短期股价预测,但股票行情受政策、消息、市场情绪等多重因素影响,本结果仅为技术学习使用,不构成投资建议

十二、完整源码汇总

python

运行

# ==================== 1. 导入库 + 环境配置 ====================
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from pyecharts.charts import Kline
from pyecharts import options as opts
import webbrowser, os
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score
from statsmodels.tsa.arima.model import ARIMA

# 解决中文、负号显示问题
plt.rcParams["axes.unicode_minus"] = False
plt.rcParams["font.family"] = "SimHei"

# ==================== 2. 数据读取与探索 ====================
df = pd.read_excel("股价数据.xlsx")
print("数据前5行:")
print(df.head())
print("\n数据基本信息:")
df.info()
print("\n缺失值统计:")
print(df.isnull().sum())

# ==================== 3. 数据预处理 ====================
df['date'] = pd.to_datetime(df['date'])
df.sort_values(by='date', inplace=True)
df = df[['date','open','close','high','low', 'volume','p_change','ma5','ma10','ma20']]
df.reset_index(drop=True, inplace=True)
print("\n预处理后数据:")
print(df.head())

# ==================== 4. 数据可视化 ====================
# 4.1 收盘价与均线
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.title('收盘价与均线走势')
plt.legend()
plt.grid(alpha=0.3)
plt.show()

# 4.2 K线图
y_data = df[['open','close','high','low']].values.tolist()
x_data = df['date'].tolist()
kline = (
    Kline()
    .add_xaxis(x_data)
    .add_yaxis("股票K线", y_data)
    .set_global_opts(
        title_opts=opts.TitleOpts(title="股票行情K线图"),
        toolbox_opts=opts.ToolboxOpts(is_show=True)
    )
)
html_name = "股票K线.html"
kline.render(html_name)
webbrowser.open("file://"+os.path.abspath(html_name))

# 4.3 成交量
plt.figure(figsize=(14,6))
plt.bar(df['date'],df['volume'])
plt.title('股票成交量柱状图')
plt.show()

# 4.4 涨跌幅分布
plt.figure(figsize=(14,6))
plt.hist(df['p_change'],bins=40)
plt.axvline(0, color='red',linestyle='--',label='涨跌分界线')
plt.legend()
plt.title('股票单日涨跌幅分布直方图')
plt.show()

# ==================== 5. 特征工程 + 数据集划分 ====================
df["close_lag1"] = df["close"].shift(1)
df = df.dropna()
split = int(len(df)*0.8)
train = df.iloc[:split]
test = df.iloc[split:]
feature_cols = ["close_lag1", "open","ma5"]
X_train = train[feature_cols]
y_train = train["close"]
X_test = test[feature_cols]
y_test = test["close"]
print(f"\n训练集:{len(train)} 条 | 测试集:{len(test)} 条")

# ==================== 6. 模型评估函数 ====================
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"R2(拟合度):{r2:.2f}")

# ==================== 7. 线性回归模型 ====================
lr = LinearRegression()
lr.fit(X_train,y_train)
y_pred_lr = lr.predict(X_test)
print("\n===== 线性回归模型评估 =====")
eval_model(y_test,y_pred_lr)

# 线性回归可视化
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()

# ==================== 8. ARIMA时间序列模型 ====================
history = list(train["close"])
predictions = []
for i in range(len(test)):
    model = ARIMA(history,order=(5,1,1))
    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()

# ==================== 9. 双模型对比 ====================
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("线性回归 VS ARIMA 预测效果对比")
plt.legend()
plt.grid(alpha=0.3)
plt.show()

# ==================== 10. 预测未来10个交易日 ====================
full_series = df["close"]
final_arima = ARIMA(full_series,order=(5,1,0)).fit()
future_pred = final_arima.get_forecast(steps=10).predicted_mean
print("\n===== 未来10个交易日预测收盘价 =====")
for i,val in enumerate(future_pred,1):
    print(f"第{i}天预测股价:{val:.2f} 元")

更多推荐