☰
iVISSA光谱特征波段筛选:原理、实践与避坑指南
2026/10/1 5:01:18 网站建设 项目流程

简介:这是一份面向光谱分析研究人员与遥感、农业、环境科学等领域从业者的iVISSA特征波段筛选工具包。该工具基于MATLAB环境运行,核心目标是从高维光谱数据中挑选信息价值最高的波段,降低数据冗余,同时提升定量预测模型的计算效率与精度,可应用于农作物组分检测、环境监测等场景。压缩包共12个文件,包含9个m格式的算法与示例脚本、2个mat格式的样本数据文件以及1个txt格式的许可说明,整体约157KB。其中m格式脚本覆盖算法主体、偏最小二乘建模、交叉验证、数据预处理等关键模块,mat文件提供示例光谱与运行结果,便于直接复现特征筛选全过程。当前已有1682人学习下载。通过该资源,读者可以快速掌握iVISSA的完整调用流程,结合自带数据复现特征波段筛选的典型过程,并以此为基础调整参数、适配自身光谱数据集,有效缩短算法开发与调试周期。

1. iVISSA光谱特征波段筛选:上百维光谱压到几十个波段,没那么玄但坑不少

做过近红外或拉曼定量建模的人,大多经历过这种场景:一条光谱几百到上千个波长点,直接全波段进模型,PLS 算得慢不说,还容易把噪声一起学进去。iVISSA 就是用来解决这个问题的——它通过迭代式的空间收缩,把原始光谱从几百维压到几十个波段,同时尽量保住与待测组分相关的信息。这套方法不是一次性计算变量权重,而是反复采样、评估、收缩,比 CARS、SPA 这类单次筛选法更能处理变量之间相关性强的光谱数据。适合做化学计量学建模的工程技术人员,尤其是手头有完整光谱数据集、希望用更稳的方式筛选特征波段的从业者。今天就从原理讲到代码,再把实操中容易翻车的地方一并说清。

2. 从VISSA到iVISSA:核心机制、改进点与三组必须调好的参数

2.1 从VISSA到iVISSA:为什么要反复迭代而不是一次筛完

传统的特征波段筛选,比如逐步回归或者无信息变量消除,本质上是在做一次性的变量选择:计算每个波长点和目标值的关系,设定阈值,保留“显著”的波段。这种做法遇到光谱数据时有个天然短板——近红外光谱中相邻波长点相关性极高,单独评估每个变量时,它们看起来都差不多,很难把真正重要的波段从冗余变量堆里揪出来。

VISSA 的思路换了一个角度:既然单次评估不可靠,那就反复抽样子集,让变量在一次次“投票”中显现出真实重要性。每一轮迭代,算法从当前候选空间中用加权二进制采样生成一批变量子集,用这些子集分别建模型并评估适应度,然后统计每个变量被选中的频率,频率高的保留,频率低的逐渐淘汰。由于每次采样都涉及变量组合,变量之间的协同效应能被保留下来,不再孤立地看单个波长点。

iVISSA 是在这个框架上的改进版本。VISSA 后期最大的问题是:当候选空间收缩到比较小时,频率估计会剧烈波动,一个波长点可能因为这轮抽样中运气好被频繁选中,下一轮又跌到谷底。iVISSA 引入了更稳定的重要性评价方式,把变量被选中频率的均值稳定性和方差稳定性联合起来作为收缩依据,同时对采样权重做了自适应的平滑更新,避免过度依赖单轮抽样结果。

2.2 核心机制拆解:加权采样、适应度评估、空间收缩三件事循环

把 iVISSA 拆开看,每一轮迭代就是三个动作:采样、评估、收缩。

第一步是加权二进制采样,缩写 WBMS。每个候选变量有一个权重,权重越高被采进子集的概率越大。每轮会生成大量子集,每个子集的规模通常由预设的最大变量数控制。第二步是适应度评估,把每个子集拉去建 PLS 模型,用交叉验证的均方根误差来衡量子集的预测能力,误差越小子集越优。第三步是空间收缩,根据这一轮所有子集的评估结果,统计每个变量在优秀子集中的出现频率,把频率低于阈值的变量从候选空间中移除,把频率高于阈值的变量权重提升。

这个过程循环下去,候选变量数量逐轮下降。与 CARS 只用指数衰减函数强制压缩不同,iVISSA 的收缩节奏是由数据自身反馈驱动的,因此对变量响应差异不显著的光谱数据更友好。下面用一段结构化的伪代码描述 iVISSA 的单轮核心逻辑,便于理解后续的工程实现:

# iVISSA 单轮迭代伪代码 for iteration in range(n_iter): # 1. 加权二进制采样:生成 n_bootstrap 个变量子集 subsets = weighted_binary_sampling(weights, n_bootstrap, max_vars) # 2. 适应度评估:每个子集用 PLS + 交叉验证打分 scores = [] for subset in subsets: pls_model = fit_pls(X[:, subset], y, n_components=k) rmsecv = cross_validate(pls_model, X[:, subset], y) scores.append(rmsecv) # 3. 确定优秀子集(如评分前 10%),统计变量选中频率 top_idx = select_top_subsets(scores, ratio=0.1) freq = count_variable_frequency(subsets, top_idx) # 4. 空间收缩:根据频率更新权重并移除低频变量 weights = update_weights(weights, freq, smoothing=alpha) candidate_vars = shrink_space(candidate_vars, freq, threshold=shrink_threshold)

这个流程里有三个关键点直接影响最终筛选效果。第一是加权采样中的权重初始值,通常设为所有变量等权,保证第一轮能均匀覆盖全谱区。第二是优秀子集的判定比例,定得太严会让收缩速度过快,错过一些协同效应;定得太松则收敛慢。第三是收缩阈值,它决定了每一轮淘汰多少变量。工程实现时,这三个点的参数设置远比算法本身更容易影响结果。

2.3 参数设计:迭代次数、采样数量、收缩阈值,给一组能用的初值

这里直接给出我常用的参数设置思路,基于实际近红外数据集整理,满足大多数场景:

参数含义推荐范围备注
n_iter迭代总轮数50 ~ 200变量数多取大值,少于 100 个变量可以取 50
n_bootstrap每轮采样子集数100 ~ 500子集越多频率统计越稳定,但算力消耗大
max_vars每个子集最大变量数30 ~ 80子集规模太大,变量组合差异不明显
top_ratio优秀子集判定比例0.05 ~ 0.15取前 5%~15% 的子集参与频率统计
shrink_threshold频率淘汰阈值0.3 ~ 0.6低于该频率的变量本轮淘汰
kPLS 潜变量个数5 ~ 15与样本量和组分复杂度相关

参数之间不是孤立的。n_bootstrap 越小,频率统计的随机性越大,这时候 shrink_threshold 要适当放大,否则会把好变量误杀。反过来,采样次数足够多时,阈值可以略微收紧。

我一般在拿到新数据集时,先固定 n_iter=100、n_bootstrap=200,把其他参数按中间值设好,跑一轮看变量数量下降曲线。如果前 20 轮变量数量就断崖式下跌,说明 shrink_threshold 定得太高,需要降下来;如果迭代快结束了候选变量还剩几百个,说明收缩太慢。这个调参过程不复杂,但直接决定筛选结果质量。

提示:iVISSA 内部每一轮的 PLS 交叉验证是主要耗时来源。n_bootstrap 从 200 提高到 500,耗时接近翻倍,收益却不一定成比例。建议先用小采样量跑通流程,再逐步加大。

3. 跑通iVISSA:数据准备、核心脚本与结果解读的完整链路

3.1 数据准备:光谱矩阵与浓度矩阵必须对齐且无缺失

开始写代码前,先把数据格式统一。由于 iVISSA 的核心评估器是 PLS,它要求输入是一个二维光谱矩阵 X 和一个一维浓度向量 y。X 的行是样本数,列是波长点,y 的长度必须等于 X 的行数。

实际操作中,最常见的低级错误是光谱矩阵和化学值来自两个不同文件,排序不一致,导致模型拟合出严重偏差。处理步骤是:先按样本编号或采集时间排序,再做缺失值检查。近红外光谱偶尔会出现个别样本在某个波长点为零或负值的情况,这是探测器漂移或保护气干扰导致的,需要先用均值插值处理掉,否则 WBMS 采样时,异常值会拉低整个子集的建模质量。

import numpy as np import pandas as pd # 读取光谱和浓度数据 spectra = pd.read_csv("spectra.csv", index_col=0) # 行是样本,列是波长点 y = pd.read_csv("reference_values.csv", index_col=0) # 化学测定值 # 按索引对齐,丢弃没有化学值的样本 common_idx = spectra.index.intersection(y.index) X = spectra.loc[common_idx].values y = y.loc[common_idx].values.ravel() # 缺失值处理:按列均值填充 col_mean = np.nanmean(X, axis=0) indices = np.where(np.isnan(X)) X[indices] = np.take(col_mean, indices[1]) print(f"光谱矩阵形状: {X.shape}, 浓度向量长度: {y.shape[0]}")

这段代码的逻辑很直接:先取交集保证光谱和化学值一一对应,再用均值填充缺失波长点。要注意的是np.nanmean计算时忽略 NaN,而填充用的np.take按列索引取均值,这两步配合能处理大部分底层数据质量问题。

3.2 核心代码:加权二进制采样与迭代收缩的完整实现

下面给出一个可直接运行的 iVISSA 核心实现,依赖 numpy、sklearn 和 scipy。这个版本没有过度优化,但结构完整,适合理解算法流程后自行扩展。

import numpy as np from sklearn.cross_decomposition import PLSRegression from sklearn.model_selection import cross_val_predict from sklearn.metrics import mean_squared_error from scipy.stats import rankdata def rmsecv_score(X_sub, y, n_components=10, cv_folds=5): """计算PLS交叉验证均方根误差,作为子集适应度""" pls = PLSRegression(n_components=n_components) y_pred = cross_val_predict(pls, X_sub, y, cv=cv_folds) return np.sqrt(mean_squared_error(y, y_pred)) def ivissa(X, y, n_iter=100, n_bootstrap=200, max_vars=50, top_ratio=0.1, shrink_threshold=0.4, k=10, seed=42): """iVISSA迭代空间收缩筛选特征波段""" rng = np.random.default_rng(seed) n_samples, n_vars = X.shape # 初始化:所有变量等权 weights = np.ones(n_vars) / n_vars active_idx = np.arange(n_vars) history = [] # 保存每轮活跃变量数 for it in range(n_iter): # 加权二进制采样:根据权重随机生成子集 subsets = [] for _ in range(n_bootstrap): # 每个变量按伯努利分布采样,概率正比于权重 prob = weights.copy() prob = prob / prob.sum() mask = rng.random(n_vars) < prob # 控制子集大小不超过 max_vars if mask.sum() > max_vars: top_pos = np.argsort(prob)[::-1][:max_vars] mask = np.zeros(n_vars, dtype=bool) mask[top_pos] = True if mask.sum() == 0: # 兜底:至少选一个变量 mask[rng.integers(0, n_vars)] = True subsets.append(mask) # 评估每个子集的适应度 scores = np.empty(n_bootstrap) for i, mask in enumerate(subsets): scores[i] = rmsecv_score(X[:, mask], y, n_components=k) # 找出优秀子集,统计变量选中频率 n_top = max(1, int(n_bootstrap * top_ratio)) top_idx = np.argsort(scores)[:n_top] freq = np.zeros(n_vars) for i in top_idx: freq[subsets[i]] += 1 freq /= n_top # 空间收缩:低于阈值的变量淘汰 keep_mask = freq >= shrink_threshold active_idx = active_idx[keep_mask[active_idx]] weights = freq.copy() weights[~keep_mask] = 0.0 history.append(len(active_idx)) if len(active_idx) <= 5: # 变量数足够少时提前终止 break return active_idx, freq[active_idx], history

逻辑说明:函数主体按“采样—评估—收缩”循环执行。n_bootstrap决定每轮生成的子集数量,max_vars限制子集规模上限;当随机采样产生的变量数超过上限时,按权重降序截断到前max_vars个。适应度评估统一用 5 折交叉验证的 RMSECV,比单次划分训练集测试集更稳定。空间收缩用频率阈值直接淘汰变量,同时把存活变量的权重更新为频率值,下一轮采样时频率高的变量被选中的概率更大。

参数说明:top_ratio=0.1意味着每轮只有评分前 10% 的子集参与频率统计,这个值建议先保持不动。shrink_threshold=0.4表示变量必须在优秀子集中出现至少 40% 的次数才能存活,设置过高会导致前几轮就淘汰过多变量。k=10是 PLS 潜变量数,实际操作中最好结合样本量调整,样本少于 50 个时建议降到 5 左右。

3.3 结果解读:变量频率图与筛选后的建模验证

算法跑完,拿到的是active_idx和对应的频率数组。但筛选完不代表工作结束,还要验证这些波段是不是真的有效。我习惯做两件事:画变量频率直方图,以及对比筛选前后的 PLS 模型表现。

import matplotlib.pyplot as plt # 绘制筛选后变量的频率分布 wavelengths = spectra.columns[active_idx] plt.bar(wavelengths, freq_sorted, width=2.0, color="#2c7fb8") plt.xlabel("Wavelength (nm)") plt.ylabel("Selection Frequency") plt.title("iVISSA Selected Bands with Frequencies") plt.show() # 对比全波段与筛选波段的模型性能 pls_full = PLSRegression(n_components=k) y_pred_full = cross_val_predict(pls_full, X, y, cv=5) rmsecv_full = np.sqrt(mean_squared_error(y, y_pred_full)) X_sel = X[:, active_idx] pls_sel = PLSRegression(n_components=k) y_pred_sel = cross_val_predict(pls_sel, X_sel, y, cv=5) rmsecv_sel = np.sqrt(mean_squared_error(y, y_pred_sel)) print(f"全波段 RMSECV: {rmsecv_full:.4f}") print(f"筛选波段 RMSECV: {rmsecv_sel:.4f}")

频率直方图的用途是判断筛选结果是否集中在少数几个谱区。如果筛选出来的波段零散分布在整条光谱上,且频率都卡在阈值附近,说明 iVISSA 没有找到明显的“特征区域”,这时候优先怀疑数据预处理或者组分与光谱的相关性本身较弱。如果频率高亮集中在特定谱区,比如近红外的一级倍频区或组合频区,那结果可信度高。

注意:筛选后 RMSECV 不一定比全波段低,只要相差不大且变量数大幅减少,筛选就是有效的。变量从 500 个降到 40 个,RMSECV 从 1.52 升到 1.55,换来的是模型简化和过拟合风险下降,这笔账是划算的。

4. 算法选型:iVISSA、CARS、SPA、UVE怎么选、怎么联合用

4.1 四种主流筛选算法对比与适用场景

很多人在做特征波段筛选时,纠结的是“到底该用哪种算法”。这里给出一个基于实际场景的对比表,把 iVISSA 放进参考系:

算法核心机制主要优势主要短板适合场景
CARS蒙特卡洛采样 + 指数衰减变量压缩迭代速度快,变量淘汰干脆对强相关变量群容易误删中等维度光谱,建模型前快速粗筛
SPA投影操作依次选择代表性变量变量间共线性控制好,结果稳定每次只能选一个,效率低变量数少、波长点密集的光谱
UVE回归系数与噪声阈值对比剔除变量能有效剔除纯噪声变量阈值靠人为设定,主观性强基线漂移严重的拉曼光谱
iVISSA迭代空间收缩 + 加权重采样频率统计变量协同效应保留好,稳定性高计算量大,参数多高维近红外光谱,精细筛选

选择的标准很简单:如果目的是快速压维,CARS 就够了;如果关心变量之间的共线性,SPA 更直接;如果噪声干扰严重,UVE 可以打底。但如果你要的是一个稳定性高、能反复使用、且解释性强的筛选结果,iVISSA 通常是首选。

4.2 联合筛选策略:iVISSA 粗筛定谱区,SPA 精筛去冗余

iVISSA 频率高只能说明这个变量和组分相关性强,不代表变量之间没有冗余。相邻的 20 个波长点可能频率全部很高,但其中 19 个的信息几乎重复。这时候我常用一个组合拳:先用 iVISSA 从全谱中筛出几个谱区,再用 SPA 在每个谱区内选真正有代表性的波长点。

from scipy.spatial.distance import cdist def spa_selection(X_candidates, n_select): """简单版SPA:投影操作逐次选择代表性变量""" n_samples, n_vars = X_candidates.shape selected = [] candidate_indices = list(range(n_vars)) # 选择范数最大的变量作为第一个投影基准 norms = np.linalg.norm(X_candidates, axis=0) first_idx = np.argmax(norms) selected.append(first_idx) for _ in range(1, n_select): # 计算当前选中变量与其他变量的相关性,选相关性最小的 current_vec = X_candidates[:, selected[-1]] correlations = np.abs(X_candidates.T @ current_vec) correlations[selected] = np.inf next_idx = np.argmin(correlations) selected.append(next_idx) return selected # 假设 ivissa_result 是上一节 iVISSA 输出的活跃波长索引 # 从活跃波段中再做 SPA 精筛,选 15 个代表波长 spa_indices = spa_selection(X[:, ivissa_result], n_select=15) final_wavelengths = wavelengths[ivissa_result][spa_indices]

这里的核心逻辑是:iVISSA 负责“划定势力范围”,SPA 负责“在这个范围内挑代表”。两步串联后,最终的变量数量可以压得更低,而且变量之间的相关性问题也被兜住了。

参数说明:spa_selection里的n_select取决于你最终想保留多少个波长点,一般取 10~20 就足够建模。实际中不要贪多,SPA 选出的变量过多时,后选出来的变量往往是被迫加入的,信息增益很低。

4.3 用模型验证筛选择优:RMSECV、R² 与变量数的综合权衡

筛选算法好不好,最终要看模型表现。这里的关键不是看单一指标,而是综合看三个维度:RMSECV、决定系数 R² 和变量数。三者的关系是:变量数从 500 降到 50,RMSECV 略有上升,但模型复杂度和过拟合风险大幅下降,这是可以接受的;RMSECV 显著恶化超过 10%,那要回头审视筛选参数。

from sklearn.metrics import r2_score y_pred_cv = cross_val_predict(pls_sel, X_sel, y, cv=5) r2_sel = r2_score(y, y_pred_cv) print(f"筛选后变量数: {X_sel.shape[1]}") print(f"RMSECV: {rmsecv_sel:.4f}") print(f"R²: {r2_sel:.4f}")

我一般会根据这三个指标决定是否保留筛选结果。如果 RMSECV 和全波段持平甚至更好,直接定稿;差一点但在可接受范围内,结合变量数的降幅,依然值得保留;差距过大就用不同的参数重新跑一轮,不要硬着头皮用。

5. 避坑手册:iVISSA筛选实操中的五个典型翻车现场

5.1 结果对随机种子敏感,换一次 seed 波段全变

现象:同一份数据,只改了随机种子,iVISSA 筛出的波段换了三四成,稳定性堪忧。

原因:加权二进制采样本质上是随机过程,n_bootstrap 不足时,频率统计的方差很大。频率恰好卡在阈值附近的变量,去留完全由随机波动决定。这算是这个算法最经典的玄学现场。

解决:不要单次跑完就定结果。固定一个随机种子跑完以后,再换 5 个不同的种子各跑一遍,把每次筛出的波段取交集或并集,只保留至少在 5 次中出现过 3 次的变量。这个“多数表决”的做法被验证能显著提升筛选稳定性。

from collections import Counter def run_ivissa_multiple(X, y, n_runs=5): """多次运行 iVISSA,统计变量被保留的频次""" counter = Counter() for seed in range(100, 100 + n_runs): idx, _, _ = ivissa(X, y, seed=seed) counter.update(idx.tolist()) # 至少在 60% 的运行中保留下来的变量 stable_vars = [v for v, c in counter.items() if c >= int(0.6 * n_runs)] return stable_vars

5.2 迭代早期变量数骤降,还没细化就提前收敛

现象:第 10 轮迭代时活跃变量从 500 直接降到 80,后面几十轮几乎没怎么变化。

原因:shrink_threshold 设置的频率阈值偏高,第一轮采样的随机性导致大量变量频率刚低于阈值就被淘汰,而其中一部分是有用的协同变量。

解决:把 shrink_threshold 从 0.4 降到 0.2~0.3,同时增大 n_bootstrap 到 300 以上,让频率估计更平滑。另一招是给每一轮的淘汰数量设上限,比如每轮最多淘汰当前变量数的 30%。

注意:迭代曲线应当呈现“缓坡下降”的形状,而不是断崖下跌。看到断崖先调阈值,不要怀疑数据。

5.3 筛选出的波段扎堆在光谱两端

现象:最终选出的变量大多数集中在光谱首尾 100 个波长点内,中间响应强的区域反而没进去。

原因:光谱两端往往是基线漂移严重的区域,信噪比低但响应幅度大,PLS 建模时这些变量容易被赋予较大权重,导致 iVISSA 的频率统计偏向它们。

解决:筛选前先做光谱预处理,比如标准正态变量变换或一阶导,把基线效应剥离。另一个办法是直接先手动剔除光谱两端的低信噪比区域,再进 iVISSA。

5.4 交叉验证分组不随机,RMSECV 虚低

现象:筛选后的 RMSECV 低得离谱,但在独立测试集上表现平平。

原因:样本按采集批次排列,交叉验证随机分组时,同一批次的样本被同时分到训练集和验证集,造成数据泄漏。光谱仪不同时间段的基线差异被模型当作有效信息学进去了。

解决:交叉验证改为按批次分组,用GroupKFold替代普通 KFold,保证同一批次的样本不出现在训练集和验证集两侧。

from sklearn.model_selection import GroupKFold # 假设 group_id 是每个样本对应的采集批次 gkf = GroupKFold(n_splits=5) cv_scores = [] for train_idx, val_idx in gkf.split(X_sel, y, groups=group_id): pls = PLSRegression(n_components=k) pls.fit(X_sel[train_idx], y[train_idx]) y_pred = pls.predict(X_sel[val_idx]) cv_scores.append(mean_squared_error(y[val_idx], y_pred, squared=False))

5.5 预处理放错了位置,筛选结果被数据泄漏污染

现象:先对全光谱做标准化再筛选,筛选结果看似稳定,但换一批样本后波段选择完全不同。

原因:如果预处理用了全体样本的统计量(比如均值、标准差),筛选过程就已经“看过”验证集的信息。这是光谱筛选里最常见的隐性数据泄漏。

解决:把预处理放进交叉验证循环内部,每一折只基于训练集计算统计量,再应用到验证集。筛选阶段只用原始光谱或只做不涉及跨样本统计的预处理,比如一阶导。

6. 进阶技巧:用多次运行投票频率验证波段稳定性

筛选算法跑完,你以为拿到结果就结束了,其实真正的确认工作才刚刚开始。我在实践里最看重的一步,是多轮运行后的投票频率验证——它比任何单次筛选结果都更能说明哪些波段是真的稳定可靠。

具体做法是:固定参数不改,用 10 个不同的随机种子各跑一遍 iVISSA,记录每个变量被保留的次数。保留次数超过 5 次的变量作为“稳定变量集”,保留次数在 3 到 5 次之间的作为“灰色变量集”,低于 3 次的直接丢弃。然后把稳定变量集建一次模型,稳定加灰色再建一次模型,比较两次的 RMSECV 差异。

def stability_analysis(X, y, n_runs=10, freq_threshold=0.5): """多次运行 iVISSA 并统计变量保留频次""" counter = Counter() for seed in range(1, n_runs + 1): idx, _, _ = ivissa(X, y, seed=seed) counter.update(idx.tolist()) total_runs = n_runs stable_vars = [v for v, c in counter.items() if c / total_runs >= freq_threshold] gray_vars = [v for v, c in counter.items() if 0.3 <= c / total_runs < freq_threshold] print(f"稳定变量数: {len(stable_vars)}") print(f"灰色变量数: {len(gray_vars)}") # 两种变量集分别建模对比 X_stable = X[:, stable_vars] rmsecv_stable = np.sqrt(mean_squared_error( y, cross_val_predict(PLSRegression(n_components=k), X_stable, y, cv=5))) X_stable_gray = X[:, sorted(stable_vars + gray_vars)] rmsecv_all = np.sqrt(mean_squared_error( y, cross_val_predict(PLSRegression(n_components=k), X_stable_gray, y, cv=5))) return stable_vars, gray_vars, rmsecv_stable, rmsecv_all

这段代码里,freq_threshold=0.5表示一个变量至少在 10 次运行中被保留 5 次,才算稳定。判定逻辑并不复杂,核心思想是:如果两个变量在物理上都很重要,它们不会因为随机种子不同而反复横跳。灰色变量集往往对应那些响应微弱但有一定作用的波段,加入它们能小幅降低 RMSECV,但代价是模型复杂性上升。

验证完毕后,如果稳定变量集单独建模的 RMSECV 与加上灰色变量集后的结果相差在 5% 以内,果断只保留稳定变量集,换来的是模型长期部署后的稳健性提升。这一点,算是我踩坑踩出来的习惯——早年做在线近红外模型时,只跑一次 iVISSA 就定了波段,结果隔了三个月用新批次样本验证,预测偏差明显变大,重新检查才发现当时筛出的变量里有不少是受环境温度影响的伪相关波段。那以后我每次做特征筛选,都强制跑 10 次、看投票频率,再决定最终波段。希望这个习惯对你也有用。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询