光谱回归建模中校正集与验证集划分:RS、KS、SPXY算法对比与Python实现

发布时间:2026/10/25 10:23:49

光谱回归建模中校正集与验证集划分:RS、KS、SPXY算法对比与Python实现 简介这份资源聚焦机器学习中校正集与验证集的划分方法面向本科、硕士及科研人员进行实验设计与教研学习帮助解决样本集合理拆分、模型评估可靠性等常见问题。包内包含SPXY算法、KS算法与RS算法三种典型划分策略的Matlab实现可直接用于光谱建模、回归预测等需要代表性样本选择的场景。资源共5个文件以4个m脚本文件和1个txt说明文件为主m文件承载各划分算法的核心代码txt则提示需自行带入数据压缩包整体约6KB轻量便于快速查阅与移植。目前已有332人学习下载读者可借此对比不同划分算法的实现思路与适用条件理解样本分布对建模结果的影响并在此基础上替换自有数据完成校正集与验证集的构建为后续模型训练与验证提供可复用的脚本参考。1. 校正集和验证集怎么分三个算法决定模型是骡子是马做回归建模的人多半遇到过这种玄学同一批光谱数据、同一个 PLSR 模型换个人重新划分校正集和验证集预测精度能从 R²0.95 掉到 0.72。这不是模型不行是划分方法在作祟。校正集calibration set用来训练模型验证集validation set用来评估模型泛化能力两者怎么切直接决定了你看到的精度是真实水平还是运气。随机划分 RS 简单粗暴但在样本分布不均时会把极端样本全塞进验证集KS 算法按光谱距离排序后等间隔抽样能保证校正集覆盖全浓度范围SPXY 算法同时考虑光谱距离和浓度距离是当前化学计量学里公认较稳的方案。这篇笔记把三种算法的原理、Python 实现、参数设置和踩坑记录一次讲透适合做近红外、拉曼、高光谱定量建模的从业者直接抄作业。2. RS、KS、SPXY 三种划分算法到底差在哪2.1 随机划分 RS最简单也最容易翻车RSRandom Sampling就是调numpy.random或sklearn的train_test_split按比例随机抽。它的假设是样本独立同分布但光谱数据往往存在浓度梯度随机抽可能导致校正集里高浓度样本扎堆、验证集里全是低浓度模型外推能力直接崩掉。我一般会先跑 RS 作为基线如果 RS 和 KS/SPXY 结果差距在 5% 以内说明样本分布本身比较均匀用 RS 省事差距大就说明数据有结构必须上 KS 或 SPXY。import numpy as np from sklearn.model_selection import train_test_split def rs_split(X, y, test_size0.3, seed42): X: 光谱矩阵 (n_samples, n_wavelengths) y: 浓度向量 (n_samples,) test_size: 验证集比例 seed: 随机种子固定后结果可复现 X_cal, X_val, y_cal, y_val train_test_split( X, y, test_sizetest_size, random_stateseed, shuffleTrue ) return X_cal, X_val, y_cal, y_val逻辑说明train_test_split默认 shuffleTruerandom_state必须固定否则每次跑结果都不一样论文里的精度没法复现。参数上test_size0.3是经验值样本量小于 100 时建议降到 0.2否则校正集样本太少模型欠拟合。2.2 KS 算法按光谱距离等间隔抽样KSKennard-Stone算法的核心思想是先选距离最远的两个样本进校正集然后每次选距离当前校正集最远的样本加入直到达到目标数量。这样校正集在光谱空间里分布最均匀。实现时用欧氏距离矩阵逐步更新最小距离。计算复杂度 O(n²)样本量上千时要注意内存。from scipy.spatial.distance import cdist def ks_split(X, y, n_cal): X: 光谱矩阵 y: 浓度向量 n_cal: 校正集样本数 n X.shape[0] D cdist(X, X, metriceuclidean) # 距离矩阵 cal_idx [] # 选距离最远的两个样本 i, j np.unravel_index(np.argmax(D), D.shape) cal_idx.extend([i, j]) # 剩余样本 remaining list(set(range(n)) - set(cal_idx)) while len(cal_idx) n_cal: # 每个剩余样本到校正集的最小距离 min_d [np.min(D[k, cal_idx]) for k in remaining] next_idx remaining[np.argmax(min_d)] cal_idx.append(next_idx) remaining.remove(next_idx) val_idx list(set(range(n)) - set(cal_idx)) return X[cal_idx], X[val_idx], y[cal_idx], y[val_idx]逻辑说明cdist算全距离矩阵np.argmax(D)找全局最远点对作为种子。循环里min_d是每个候选样本到已选集合的最近距离选最大的那个加入保证新样本离现有校正集最远。参数n_cal一般取总样本的 70%~80%样本量少于 50 时建议 80%。注意KS 只考虑光谱距离如果浓度分布不均匀可能出现校正集光谱覆盖好但浓度范围窄的情况这时候要上 SPXY。2.3 SPXY 算法光谱距离和浓度距离一起算SPXYSample set Partitioning based on joint X-Y distances在 KS 基础上做了改进距离度量同时包含光谱距离和浓度距离归一化后相加。这样选出的校正集在光谱空间和浓度空间都均匀。公式是 d_xy d_x/d_x_max d_y/d_y_max其中 d_x 是光谱欧氏距离d_y 是浓度欧氏距离。def spxy_split(X, y, n_cal): X: 光谱矩阵 y: 浓度向量 n_cal: 校正集样本数 # 光谱距离 Dx cdist(X, X, metriceuclidean) Dx Dx / Dx.max() # 浓度距离 y_2d y.reshape(-1, 1) Dy cdist(y_2d, y_2d, metriceuclidean) Dy Dy / Dy.max() # 联合距离 D Dx Dy n X.shape[0] cal_idx [] i, j np.unravel_index(np.argmax(D), D.shape) cal_idx.extend([i, j]) remaining list(set(range(n)) - set(cal_idx)) while len(cal_idx) n_cal: min_d [np.min(D[k, cal_idx]) for k in remaining] next_idx remaining[np.argmax(min_d)] cal_idx.append(next_idx) remaining.remove(next_idx) val_idx list(set(range(n)) - set(cal_idx)) return X[cal_idx], X[val_idx], y[cal_idx], y[val_idx]逻辑说明Dx和Dy分别归一化到 [0,1] 再加权避免量纲差异导致某一项主导。Dx.max()和Dy.max()是归一化因子必须用当前数据集的最大值不能写死。参数n_cal和 KS 一致但 SPXY 对浓度梯度大的数据集更稳。提示SPXY 计算量比 KS 大样本超过 2000 时建议先做 PCA 降维再算距离否则cdist会吃满内存。3. 用 Python 把三种划分跑通从数据到精度对比3.1 数据准备和预处理拿一份近红外光谱数据举例假设X是 200×500 的矩阵y是 200 个浓度值。预处理先做 SNV标准正态变量变换消除散射影响再做一阶导数增强峰特征。import numpy as np from scipy.signal import savgol_filter def snv(X): 标准正态变量变换 mean X.mean(axis1, keepdimsTrue) std X.std(axis1, keepdimsTrue) return (X - mean) / std def first_derivative(X, window11, poly2): Savitzky-Golay 一阶导数 return savgol_filter(X, window_lengthwindow, polyorderpoly, deriv1, axis1) # 假设 X_raw, y 已加载 X snv(X_raw) X first_derivative(X)逻辑说明snv按行做标准化消除样本间基线漂移。savgol_filter的window_length必须奇数polyorder小于window_length一阶导数用deriv1。参数window11是经验值光谱分辨率高时可以调到 15 或 21。3.2 三种划分的完整调用和建模用 PLSR偏最小二乘回归做模型统一用 10 折交叉验证选主成分数然后看验证集 RMSEP 和 R²。from sklearn.cross_decomposition import PLSRegression from sklearn.metrics import mean_squared_error, r2_score def evaluate_split(X_cal, X_val, y_cal, y_val, n_components10): pls PLSRegression(n_componentsn_components) pls.fit(X_cal, y_cal) y_pred pls.predict(X_val).ravel() rmsep np.sqrt(mean_squared_error(y_val, y_pred)) r2 r2_score(y_val, y_pred) return rmsep, r2 # RS X_cal_rs, X_val_rs, y_cal_rs, y_val_rs rs_split(X, y, test_size0.3, seed42) rmsep_rs, r2_rs evaluate_split(X_cal_rs, X_val_rs, y_cal_rs, y_val_rs) # KS X_cal_ks, X_val_ks, y_cal_ks, y_val_ks ks_split(X, y, n_cal140) rmsep_ks, r2_ks evaluate_split(X_cal_ks, X_val_ks, y_cal_ks, y_val_ks) # SPXY X_cal_spxy, X_val_spxy, y_cal_spxy, y_val_spxy spxy_split(X, y, n_cal140) rmsep_spxy, r2_spxy evaluate_split(X_cal_spxy, X_val_spxy, y_cal_spxy, y_val_spxy) print(fRS: RMSEP{rmsep_rs:.4f}, R2{r2_rs:.4f}) print(fKS: RMSEP{rmsep_ks:.4f}, R2{r2_ks:.4f}) print(fSPXY: RMSEP{rmsep_spxy:.4f}, R2{r2_spxy:.4f})逻辑说明PLSRegression的n_components是主成分数一般通过交叉验证确定这里固定 10 方便对比。evaluate_split返回 RMSEP 和 R²RMSEP 越小、R² 越接近 1 越好。实际跑下来SPXY 通常比 RS 的 RMSEP 低 10%~30%KS 介于两者之间。3.3 参数怎么调校正集比例和主成分数校正集比例不是固定的。样本量 50~100 时校正集占 80%100~500 时70%~75%超过 500 时60%~70% 就够。主成分数用交叉验证的 RMSECV 最小值确定不要超过校正集样本数的 1/10。样本量校正集比例主成分数上限5080%550-10075%-80%8100-50070%-75%1550060%-70%20注意主成分数过多会过拟合RMSEC 很低但 RMSEP 很高这时候要回头检查划分方法是不是把异常样本漏进校正集了。4. 避坑记录划分校正集和验证集时最容易翻车的 5 个点4.1 现象RS 每次跑精度都不一样论文没法复现原因train_test_split没固定random_state或者用了shuffleTrue但没设种子。解决所有随机操作必须固定种子seed42是惯例写进代码注释里。4.2 现象KS 选出的校正集浓度范围比验证集窄原因KS 只按光谱距离选样本如果浓度和光谱不是强相关会出现光谱覆盖好但浓度覆盖差的情况。解决换 SPXY或者先按浓度分层再做 KS。4.3 现象SPXY 跑得特别慢内存爆了原因cdist算的是 n×n 全距离矩阵样本 5000 时矩阵是 5000×5000float64 占 200MB加上中间变量直接吃满。解决先做 PCA 降到 20~50 维再算距离或者用scipy.spatial.distance.pdist算压缩距离。4.4 现象校正集 R²0.99验证集 R²0.6原因校正集里混入了异常样本或者校正集和验证集有重叠。解决建模前用马氏距离或 PCA 的 Hotelling T² 筛异常样本划分后检查两个集合的索引有没有交集。4.5 现象换了批次数据SPXY 效果还不如 RS原因不同批次的光谱基线差异大直接算欧氏距离会把批次差异当成样本差异。解决先做批次校正如 PDS、OSC再跑 SPXY。如果批次效应太强考虑按批次分层划分。5. 进阶技巧用 Kennard-Stone 的变体做分层 SPXY标准 SPXY 有个隐患如果浓度分布本身不均匀比如低浓度样本占 80%联合距离会被浓度项主导选出的校正集在光谱空间反而稀疏。我一般会做分层 SPXY先按浓度分箱每个箱内按比例抽样本再在抽出的样本上跑 SPXY。def stratified_spxy_split(X, y, n_cal, n_bins5): 分层 SPXY先按浓度分箱每箱按比例抽候选样本再跑 SPXY bins np.linspace(y.min(), y.max(), n_bins 1) bin_idx np.digitize(y, bins) - 1 bin_idx np.clip(bin_idx, 0, n_bins - 1) candidate_idx [] for b in range(n_bins): idx_b np.where(bin_idx b)[0] n_b max(2, int(len(idx_b) * n_cal / len(y))) n_b min(n_b, len(idx_b)) chosen np.random.choice(idx_b, n_b, replaceFalse) candidate_idx.extend(chosen) candidate_idx np.array(candidate_idx) X_sub, y_sub X[candidate_idx], y[candidate_idx] X_cal_sub, X_val_sub, y_cal_sub, y_val_sub spxy_split(X_sub, y_sub, n_calmin(n_cal, len(candidate_idx))) # 映射回原始索引 return X_cal_sub, X_val_sub, y_cal_sub, y_val_sub逻辑说明np.digitize按浓度分箱每个箱按比例抽候选样本保证低浓度和高浓度都有代表。n_b max(2, ...)保证每箱至少 2 个样本否则 SPXY 选不出距离最远点对。参数n_bins5是经验值浓度范围跨两个数量级时用 8~10 箱。验证方法跑 10 次不同随机种子的分层 SPXY看 RMSEP 的均值和标准差。如果标准差小于 0.05说明划分稳定如果大于 0.1说明数据本身有问题先查异常样本和批次效应。我自己的习惯是拿到新数据先跑 RS 看基线再跑 KS 和 SPXY 对比如果 SPXY 比 RS 的 RMSEP 低不到 5%说明数据分布均匀直接用 RS 省时间如果低 15% 以上必须用 SPXY并且把划分代码和随机种子一起存档不然三个月后回头复现就是一场血泪史。希望帮到你。本文还有配套的精品资源点击获取
延伸阅读

更多相关文章

2026/10/25 10:23:49

C++与Python协同实现AlphaGo Zero围棋AI系统

简介:本资源是一份面向AI算法研究者与深度学习开发者的AlphaGoZero围棋AI复现工程,聚焦强化学习、蒙特卡洛树搜索(MCTS)与双头神经网络(策略价值)的工程落地。项目完整实现从自我对弈数据生成、C/Python混合…

2026/10/25 10:23:49

手写中文分词器:从词典匹配到FMM/BMM/BiMM实现

简介:本资源是一份面向高校自然语言处理课程学习者的高分大作业实践方案,聚焦基于词典的中文分词方法实现,适用于期末大作业、课程设计及NLP入门项目实战。代码采用Python编写,结构清晰、注释详尽,配套完整实验报告&am…

2026/10/25 10:18:48

基于知识图谱与神经网络的简历推荐系统毕业设计实战

简介:这份资源是面向高校计算机相关专业学生的Python毕业设计完整项目,主题为基于知识图谱与人工神经网络的简历推荐系统,适合作为毕设、期末大作业或课程设计的高分参考方案。项目将知识图谱构建与深度神经网络模型相结合,实现简…

2026/10/25 11:28:54

机器学习算法公式解析:从理论到实践的三层境界

1. 机器学习算法公式的深度解读价值第一次看到这个标题时,我正坐在工位上调试一个随机森林模型。屏幕上密密麻麻的公式让我突然意识到:虽然每天都在用这些算法,但有多少人真正理解它们背后的数学原理?这就像开车多年却从未打开过引…

2026/10/25 11:28:54

加窗傅里叶变换:频谱泄漏与窗函数权衡原理

简介:本资源是一份面向信号处理初学者与MATLAB入门学习者的教学演示程序,聚焦加窗傅里叶变换的核心原理与实践对比,解决有限长信号频谱泄漏导致分析失真这一典型问题。程序通过生成正弦波信号,分别施加方窗(矩形窗&…

2026/10/25 11:28:54

梦幻古龙GDF文件解包打包实战:从二进制解析到资源重建

简介:一份面向《梦幻古龙》游戏资源处理的 C 源码包,适用于游戏开发、资源逆向与自定义工具编写者。资源围绕 GDF(Game Data Format)文件格式展开,核心代码将文件操作、批量管理与数据流读写分成多个模块:G…

2026/10/25 11:28:54

多模态融合情感分析:从文本到四类情感的Python分层方案

简介:一套基于Python与TensorFlow实现的多模态情感分析项目资源,输入涵盖文本、语音、图片和视频,面向毕业设计、课程设计与项目开发。源码已通过严格测试,可放心参考并二次扩展。项目采用分层融合思路:先提取单模态特…

2026/10/25 11:28:54

OpenCvSharp4.1例程实战:Mat、Canny与视频链路调参排错

简介:面向 C# 开发者的 OpenCvSharp4.1 官方例程合集,适合已具备一定 .NET 基础、希望对照官方示例学习 OpenCV 4.1 图像处理与计算机视觉 API 的读者。包内共 176 个文件,以 60 个 cs 源码和少量 vb 示例为主体,辅以 jpg、png、b…

2026/10/25 11:23:54

MATLAB二维声波逆时偏移成像最小闭环与照明补偿

简介:面向地震勘探资料处理学习者与地球物理专业师生的MATLAB偏移成像代码合集,聚焦校正反射点位置、消除波传播造成的成像畸变,适合具备一定MATLAB基础、希望从脚本层面理解偏移算法实现的中高级读者。压缩包共24个文件,全部为.m…

2026/10/25 0:02:22

全国计算机二级C语言真题PDF高效刷题指南

简介:这份PDF是全国计算机二级C语言考试的试题与答案解析,专为备考二级C语言的考生准备。内容涵盖C语言特点与设计理念、程序基本组成单位、main函数执行流程、函数嵌套调用规则、标识符命名规范、整型实型字符型数据类型、八进制十六进制数合法形式、运…

2026/10/25 0:02:23

requests+BeautifulSoup:爬虫抓取h1标题的入门实战指南

简介:一份以实战为导向的Python爬虫入门资源,面向具备基本编程基础、希望快速掌握网络数据抓取的初学者,可解决从零编写简单爬虫的常见困惑。实例以requests库发送HTTP请求、BeautifulSoup解析HTML文档,完整演示从网页中提取 标题…

2026/10/25 0:02:23

递推最小二乘参数辨识MATLAB编程:二阶系统与渐消记忆实现

简介:这是一篇面向控制系统、信号处理与机器学习等领域学习者的最小二乘参数辨识程序说明文档。资源共包含一个docx格式文档,压缩包大小七十八KB,内容围绕递推最小二乘算法和渐消记忆最小二乘算法展开:先构造一个极点位于单位圆内…

2026/10/25 0:02:22

全国计算机二级C语言真题PDF高效刷题指南

简介:这份PDF是全国计算机二级C语言考试的试题与答案解析,专为备考二级C语言的考生准备。内容涵盖C语言特点与设计理念、程序基本组成单位、main函数执行流程、函数嵌套调用规则、标识符命名规范、整型实型字符型数据类型、八进制十六进制数合法形式、运…

2026/10/25 0:02:23

requests+BeautifulSoup:爬虫抓取h1标题的入门实战指南

简介:一份以实战为导向的Python爬虫入门资源,面向具备基本编程基础、希望快速掌握网络数据抓取的初学者,可解决从零编写简单爬虫的常见困惑。实例以requests库发送HTTP请求、BeautifulSoup解析HTML文档,完整演示从网页中提取 标题…

2026/10/25 0:02:23

递推最小二乘参数辨识MATLAB编程:二阶系统与渐消记忆实现

简介:这是一篇面向控制系统、信号处理与机器学习等领域学习者的最小二乘参数辨识程序说明文档。资源共包含一个docx格式文档,压缩包大小七十八KB,内容围绕递推最小二乘算法和渐消记忆最小二乘算法展开:先构造一个极点位于单位圆内…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑