Matlab PLS回归代码转Python后结果差异问题求助
Matlab与Python PLSR模型结果差异问题分析与解决办法
问题描述
我需要将Matlab中实现的偏最小二乘回归(PLSR)代码转换为Python版本,原Matlab代码包含15个潜变量、5折交叉验证、100次蒙特卡洛重复。使用sklearn完成Python代码编写后,发现Matlab版本模型的R²均≥0.5,但Python版本的R²接近0甚至为负,求差异原因及解决办法。
Matlab代码实现
% PLSR with 15 latent variables [~,~,~,~,~,MSEcv] = plsregress(X,y,15,"cv",5,"MCReps",100); rRMSE = 100*sqrt(MSEcv(2,:))/(max(y)-min(y)); % 修正原代码括号语法错误 % Find optimal number of latent variables minl = 1; maxl = 15; nlv = find(rRMSE(minl+1:maxl+1)==min(rRMSE(minl+1:maxl+1)))-1+minl; nlv = nlv(1); % Fit with optimal number of latent variables [XL,yl,XS,YS,beta,PCTVAR,MSE,stats] = plsregress(X,y,nlv); % 修正原代码分号语法错误
说明:最大15个潜变量,5折交叉验证,100次蒙特卡洛重复
Python代码实现
import numpy as np from sklearn.cross_decomposition import PLSRegression from sklearn.model_selection import cross_validate from sklearn.model_selection import ShuffleSplit import pandas as pd # 读取数据 X = pd.read_table("/path/to/saved/files/X.txt", header=None) y = pd.read_table("/path/to/saved/files/y.txt", header=None) # Maximum number of latent variables mlv = 15 # Cross-validation cv = 5 # Monte-Carlo repetitions mcr = 100 # 1...mlv to fit models with various number of latent variables try_latent_vars = np.arange(1, mlv) ##----------------------------------------------------------------------------| # Define funtion to fit PLSmodel def optimise_pls_cv(X_vals, y_vals, n_comp, crossval, mcreps): '''Fit PLS regression model using cross-validation.''' # Define PLS object pls = PLSRegression(n_components=n_comp) # Cross-validation fit cv_split = ShuffleSplit(n_splits=mcreps, test_size=1/crossval, random_state=0) cvs = cross_validate(pls, X_vals, y_vals, cv=cv_split, scoring=["r2", "neg_mean_squared_error"]) mean_r2_error = np.mean(cvs["test_r2"]) test_mse = -np.mean(cvs["test_neg_mean_squared_error"]) return pls, mean_r2_error, test_mse ##----------------------------------------------------------------------------| # Fit PLS model # Empty lists to store R^2 and mean squared error values r2s = [] mses = [] for n_comp in try_latent_vars: model, r2, mse = optimise_pls_cv(X_vals=X.T, y_vals=y, n_comp=n_comp, crossval=cv, mcreps=mcr) r2s.append(r2) mses.append(mse) index_max_r2s = np.argmax(r2s) lv = try_latent_vars[index_max_r2s] ##----------------------------------------------------------------------------| ## Fit model with optimized number of components model, r2, mse = optimise_pls_cv(X_vals=X.T, y_vals=y, n_comp=lv, crossval=cv, mcreps=mcr) metrics = {"R2": r2, "MSE": mse} metrics_str = "R2: %0.4f, MSE: %0.4f" % (r2, mse)
差异原因分析
- 数据维度错误:Matlab中
plsregress默认输入X为[样本数×特征数]格式,而Python代码中直接使用X.T,若读取的X本身已是样本×特征的结构,转置后会变成特征×样本,导致模型输入维度完全颠倒,无法有效学习。 - 潜变量遍历范围缺失:Python中
try_latent_vars = np.arange(1, mlv)仅遍历1到14个潜变量,遗漏了Matlab中包含的15个潜变量的情况,可能最优潜变量恰好是15。 - 交叉验证策略不一致:Matlab的
MCReps=100是重复5折交叉验证100次,而Python使用ShuffleSplit做100次随机拆分(每次按4:1划分训练/测试集),两种拆分策略的数据分布匹配度不同,导致评估结果差异。 - 目标变量格式问题:读取的
y是pandas DataFrame(二维结构),sklearn模型更适合接收一维数组输入,二维输入可能导致模型处理异常。 - 预处理细节差异:虽两者默认都对数据中心化,但需确认是否存在缩放等其他预处理差异(Matlab默认不缩放,sklearn的
PLSRegression默认也不缩放,但需显式确认)。
解决办法
- 修正数据维度:先打印
X.shape确认维度,若为(n_samples, n_features),则直接使用X.values而非X.T;若原始数据是特征×样本格式,再保留转置。 - 补全潜变量遍历范围:将
try_latent_vars改为np.arange(1, mlv+1),确保包含15个潜变量的情况。 - 统一交叉验证策略:使用
RepeatedKFold替代ShuffleSplit,完全匹配Matlab的重复5折交叉验证逻辑:from sklearn.model_selection import RepeatedKFold cv_split = RepeatedKFold(n_splits=cv, n_repeats=mcreps, random_state=0) - 调整目标变量格式:将
y转为一维数组,比如在调用函数时传入y_vals = y.values.ravel()。 - 显式设置预处理参数:初始化
PLSRegression时显式指定center=True, scale=False,确保与Matlab的预处理逻辑一致:pls = PLSRegression(n_components=n_comp, center=True, scale=False)
内容的提问来源于stack exchange,提问作者Manuel Popp
相关产品推荐
相关产品推荐

