本文提供期魔方【经典机器学习模型-线性回归】的完整示例:用前一天的铁矿石价格预测当天螺纹钢收盘价,涵盖数据获取、特征工程、训练评估、可视化、保存加载全过程。各环节的详细讲解见机器学习流程详解。
案例背景
本案例使用机器学习中的线性回归模型来预测螺纹钢期货价格。线性回归是一种监督学习算法,用于建立一个或多个自变量(特征)与因变量(目标变量)之间的线性关系。
特征与目标变量
什么是特征(X,自变量)
在这个模型中,特征是指用于预测目标变量的输入变量。具体来说:
- 铁矿石的收盘价:这是模型中唯一的特征,用符号 X 表示。
- 数据来源:通过期魔方平台数据接口获取的铁矿石主连合约的收盘价。
- 数据处理:将前一天铁矿石的收盘价作为输入特征,用于预测当天螺纹钢的收盘价。
什么是目标变量(y,因变量)
目标变量是指模型试图预测的输出变量。在这个模型中:
- 螺纹钢的收盘价:这是模型的目标变量,用符号 y 表示。
- 数据来源:通过期魔方平台数据接口获取的螺纹钢主连合约的收盘价。
- 数据处理:将螺纹钢的收盘价作为模型的输出目标,用于评估模型的预测性能。
完整示例代码
"""
文件类型:机器学习
帮助文档:https://qmfquant.com/static/doc/code/modelEdit.html
期魔方,为您提供专业的量化服务
模型类型:经典机器学习模型-线性回归
"""
import asyncio
import os
import joblib
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import qmf_model_sdk
import seaborn as sns
from qmf_data import load_kline
from scipy import stats
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score
# 获取数据配置
symbol = "rb888"
begin_time = "2020-01-01"
end_time = "2025-05-01"
symbol_cycle = "1天"
asyncio.run(qmf_model_sdk.get_futures_data(symbol, begin_time, end_time, symbol_cycle))
symbol = "i888"
asyncio.run(qmf_model_sdk.get_futures_data(symbol, begin_time, end_time, symbol_cycle))
# 设置图形、中文及负号显示
matplotlib.use("QtAgg") # 期魔方平台图形显示必须要有这行代码
plt.rcParams["font.sans-serif"] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = False
# 获取螺纹钢主连和铁矿石主连的数据
def get_futures_data(symbol, start_time="2023-01-01 00:00:00", end_time="2025-05-01 00:00:00"):
data = load_kline(product=symbol, cycle="1D", start_time=start_time, end_time=end_time)
data["date"] = pd.to_datetime(data["date"], errors="coerce")
data.rename(columns={"close": "收盘"}, inplace=True)
data.reset_index(inplace=True, drop=True)
return data
# 获取保存模型文件的地址
def get_save_model_path(file_name):
current_file_path = os.path.abspath(__file__)
filename_without_ext = os.path.splitext(os.path.basename(current_file_path))[0]
return f"{os.path.dirname(current_file_path)}\\{filename_without_ext}__{file_name}"
# 获取数据
rbm_data = get_futures_data("rb888") # 螺纹钢主连
im_data = get_futures_data("i888") # 铁矿石主连
# 合并数据,基于日期,这样可以确保铁矿石和螺纹钢数据对齐
df = pd.merge(
rbm_data[["date", "收盘"]],
im_data[["date", "收盘"]],
on="date",
how="inner",
suffixes=("_螺纹钢", "_铁矿石"),
)
# 创建前一天的铁矿石价格列
df["前一天铁矿石收盘"] = df["收盘_铁矿石"].shift(1)
# 删除第一行,因为它没有前一天的数据
df = df.dropna()
# 建立预测模型,利用前一天铁矿石的价格预测当天螺纹钢的收盘价
X = df[["前一天铁矿石收盘"]].values
y = df["收盘_螺纹钢"].values
# 确保数据按时间排序
df = df.sort_values("date")
# 按时间顺序划分训练集和测试集(80%训练,20%测试)
train_size = int(len(df) * 0.8)
train_data = df.iloc[:train_size]
test_data = df.iloc[train_size:]
# 准备特征和目标变量
X_train = train_data[["前一天铁矿石收盘"]].values
y_train = train_data["收盘_螺纹钢"].values
X_test = test_data[["前一天铁矿石收盘"]].values
y_test = test_data["收盘_螺纹钢"].values
# 创建并训练模型
model = LinearRegression()
model.fit(X_train, y_train)
# 在训练集和测试集上进行预测
y_train_pred = model.predict(X_train)
y_test_pred = model.predict(X_test)
# 计算各种评估指标
def calculate_metrics(y_true, y_pred):
r2 = r2_score(y_true, y_pred)
mse = mean_squared_error(y_true, y_pred)
rmse = np.sqrt(mse)
mae = mean_absolute_error(y_true, y_pred)
mape = np.mean(np.abs((y_true - y_pred) / y_true)) * 100
return r2, rmse, mae, mape
# 计算训练集和测试集的评估指标
train_metrics = calculate_metrics(y_train, y_train_pred)
test_metrics = calculate_metrics(y_test, y_test_pred)
# 打印评估结果
print("\n模型评估结果:")
print("训练集:")
print(f"R²分数: {train_metrics[0]:.4f}")
print(f"RMSE: {train_metrics[1]:.2f}")
print(f"MAE: {train_metrics[2]:.2f}")
print(f"MAPE: {train_metrics[3]:.2f}%")
print("\n测试集:")
print(f"R²分数: {test_metrics[0]:.4f}")
print(f"RMSE: {test_metrics[1]:.2f}")
print(f"MAE: {test_metrics[2]:.2f}")
print(f"MAPE: {test_metrics[3]:.2f}%")
# 创建评估图
plt.figure(figsize=(20, 15))
# 实际值vs预测值图
plt.subplot(2, 2, 1)
plt.scatter(y_train, y_train_pred, c="blue", alpha=0.5, label="训练集")
plt.scatter(y_test, y_test_pred, c="red", alpha=0.5, label="测试集")
plt.plot([y.min(), y.max()], [y.min(), y.max()], "k--", lw=2)
plt.xlabel("实际值")
plt.ylabel("预测值")
plt.title("实际值 vs 预测值")
plt.legend()
# 残差图
residuals_train = y_train - y_train_pred
residuals_test = y_test - y_test_pred
plt.subplot(2, 2, 2)
plt.scatter(y_train_pred, residuals_train, c="blue", alpha=0.5, label="训练集")
plt.scatter(y_test_pred, residuals_test, c="red", alpha=0.5, label="测试集")
plt.axhline(y=0, color="k", linestyle="--")
plt.xlabel("预测值")
plt.ylabel("残差")
plt.title("残差分布图")
plt.legend()
# 残差直方图
plt.subplot(2, 2, 3)
sns.histplot(residuals_train, color="blue", alpha=0.5, label="训练集", bins=30)
sns.histplot(residuals_test, color="red", alpha=0.5, label="测试集", bins=30)
plt.xlabel("残差")
plt.ylabel("频数")
plt.title("残差直方图")
plt.legend()
# Q-Q图
plt.subplot(2, 2, 4)
stats.probplot(residuals_train, dist="norm", plot=plt)
plt.title("残差Q-Q图")
plt.tight_layout()
plt.show()
# 添加时间序列预测图
plt.figure(figsize=(15, 7))
plt.plot(train_data["date"], train_data["收盘_螺纹钢"], 'b-', label='训练集实际值')
plt.plot(train_data["date"], y_train_pred, 'g--', label='训练集预测值')
plt.plot(test_data["date"], test_data["收盘_螺纹钢"], 'r-', label='测试集实际值')
plt.plot(test_data["date"], y_test_pred, 'y--', label='测试集预测值')
plt.axvline(x=train_data["date"].iloc[-1], color='k', linestyle='--', label='训练/测试分割点')
plt.xlabel('日期')
plt.ylabel('螺纹钢收盘价')
plt.title('时间序列预测结果')
plt.legend()
plt.grid(True)
plt.tight_layout()
plt.show()
# 添加散点图显示铁矿石价格与螺纹钢价格的关系
plt.figure(figsize=(10, 6))
plt.scatter(train_data["前一天铁矿石收盘"], train_data["收盘_螺纹钢"],
c="blue", alpha=0.5, label="训练集")
plt.scatter(test_data["前一天铁矿石收盘"], test_data["收盘_螺纹钢"],
c="red", alpha=0.5, label="测试集")
# 添加回归线
x_range = np.linspace(
min(df["前一天铁矿石收盘"]),
max(df["前一天铁矿石收盘"]),
100
).reshape(-1, 1)
plt.plot(x_range, model.predict(x_range), 'k-', lw=2)
plt.xlabel('前一天铁矿石收盘价')
plt.ylabel('螺纹钢收盘价')
plt.title('前一天铁矿石价格与螺纹钢价格关系')
plt.legend()
plt.grid(True)
plt.tight_layout()
plt.show()
# 保存模型(文件名需与实盘策略中 load_model 的名称一致)
model_filename = get_save_model_path("model_lr.joblib")
joblib.dump(model, model_filename)
print(f"模型已保存至: {model_filename}")
# 加载模型示例
loaded_model = joblib.load(model_filename)
# 使用加载的模型进行预测
test_value = np.array([[800]]) # 假设前一天铁矿石价格为 800 时
predicted_price = loaded_model.predict(test_value)[0]
print("使用加载的模型预测:")
print(f"当铁矿石前一日价格为 800 时,螺纹钢当日预测价格为: {predicted_price:.2f}")
代码结构说明
本案例代码按工作流程可分为六个部分:
- 数据获取:通过 qmf_model_sdk 下载螺纹钢、铁矿石历史数据,再用 load_kline 读取
- 特征工程:按日期合并对齐两个品种数据,构建"前一天铁矿石收盘"特征,划分训练集/测试集
- 模型训练:LinearRegression 拟合训练集,并在训练集、测试集上分别预测
- 模型评估:计算并打印 R²、RMSE、MAE、MAPE 指标
- 可视化分析:绘制实际值vs预测值、残差分布、残差直方图、Q-Q 图、时间序列预测图、价格关系散点图
- 模型保存与加载:joblib 保存模型到本地并重新加载,用新数据(铁矿石 800 元)验证预测
相关阅读

评论
登录后参与讨论,与站内账号体系共用。