3. MATLAB调用Python机器学习模型进行预测

任务拆解与互操作链路

本案例要打通一条“Python 训练 → 模型落盘 → MATLAB 加载 → 新样本预测”的最小闭环。关键约束有三点:第一,模型必须保存为 MATLAB 能直接读取的格式,最稳妥的选择是 .mat(通过 SciPy 的 savemat 写出),避免依赖 MATLAB 对 pickle 或 joblib 的间接支持;第二,MATLAB 侧只负责“加载参数 + 前向计算”,不重新训练,从而真正验证互操作而非重复建模;第三,输入特征顺序、标准化参数、系数排列必须在两侧严格一致,否则预测值会静默偏移。

Python 侧(训练与导出) 合成训练数据 X(80×3), y y = 2.5x₁ − 1.2x₂ + 0.8x₃ + 4 + 噪声 StandardScaler 拟合 + 变换 保存 mean_、scale_ LinearRegression 训练 得到 coef_、intercept_ savemat 写出 model.mat coef / intercept / mean / scale model.mat 4 个数值数组 无对象依赖 MATLAB 侧(加载与预测) load('model.mat') 得到 coef, intercept, mean, scale 新输入 Xnew(2×3) 按列对齐特征顺序 Z = (Xnew − mean) ./ scale yhat = Z·coef' + intercept 与 Python 预测值比对 |Δ| < 1e-10 判定通过 特征顺序、标准化参数、系数排列三处必须一致,否则预测静默偏移

Python 侧:训练并导出为 .mat

用 numpy 生成可复现的合成数据,训练标准化 + 线性回归,然后把四个数值数组写入 .mat。注意 savemat 默认按列优先存储,MATLAB 读入后是列向量,后续前向计算要按列向量处理。

# train_export.py
import numpy as np
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import StandardScaler
from scipy.io import savemat

rng = np.random.default_rng(42)
X = rng.normal(size=(80, 3))
y = 2.5*X[:,0] - 1.2*X[:,1] + 0.8*X[:,2] + 4.0 + rng.normal(scale=0.1, size=80)

scaler = StandardScaler().fit(X)
Xs = scaler.transform(X)
model = LinearRegression().fit(Xs, y)

savemat("model.mat", {
    "coef": model.coef_.reshape(-1, 1),      # 3×1
    "intercept": np.array([[model.intercept_]]),
    "mean": scaler.mean_.reshape(-1, 1),     # 3×1
    "scale": scaler.scale_.reshape(-1, 1),   # 3×1
})

# 留一份参考预测,供 MATLAB 侧比对
Xnew = np.array([[0.5, -1.0, 2.0],
                 [-0.3, 0.8, -1.5]])
yhat_py = model.predict(scaler.transform(Xnew))
np.savetxt("yhat_py.txt", yhat_py)
print("coef =", model.coef_)
print("intercept =", model.intercept_)
print("yhat_py =", yhat_py)

运行后应得到 model.mat 与 yhat_py.txt。示例数据下 coef 约为 [2.49, -1.19, 0.79],intercept 约为 4.00,具体数值以实际运行输出为准。

MATLAB 侧:加载参数并做前向计算

MATLAB 不重新训练,只复现“标准化 + 线性组合”两步。由于 coef、mean、scale 读入后是 3×1 列向量,用 Xnew * coef 即可得到 2×1 的预测列向量。

% predict_matlab.m
clear; clc;
S = load('model.mat');
coef = S.coef;  intercept = S.intercept;
mu = S.mean;    sd = S.scale;

Xnew = [0.5, -1.0, 2.0;
       -0.3,  0.8, -1.5];

Z = (Xnew - mu') ./ sd';      % 按列广播标准化
yhat = Z * coef + intercept;  % 2×1

yhat_py = readmatrix('yhat_py.txt');
diff = abs(yhat - yhat_py);
fprintf('MATLAB 预测: %.6f, %.6f\n', yhat(1), yhat(2));
fprintf('Python 预测: %.6f, %.6f\n', yhat_py(1), yhat_py(2));
fprintf('最大绝对偏差: %.3e\n', max(diff));
assert(max(diff) < 1e-10, '互操作校验失败');
若 MATLAB 侧报“矩阵维度不一致”,优先检查 mu、sd 是否为列向量。用 mu' 转成行向量再与 Xnew 相减,可避免隐式扩展方向错误。

结果判读与常见偏差

现象可能原因处理
预测值整体偏移一个常数intercept 未加或加了两次确认公式为 Z*coef + intercept
偏差随特征量级放大标准化参数方向或顺序错位核对 mean/scale 与特征列一一对应
偏差约 1e-2 量级MATLAB 侧误用了未标准化输入先做 (Xnew-mu')./sd' 再乘系数
load 后变量名不符savemat 键名与 MATLAB 变量名不一致统一使用 coef/intercept/mean/scale

通过条件是两侧预测的最大绝对偏差小于 1e-10。该阈值对双精度浮点运算足够严格,能有效暴露参数错位、漏加截距或标准化遗漏等问题,同时不会因正常舍入误差误报。