基于近红外光谱和遗传算法优化偏最小二乘法的大黄鱼品质检测研究
此外,在软件实现方面,以 MATLAB 语言和环境为支持,完成了不同光谱数据前处理方式的运算。结果表明,利用同一光谱建立的关于淀粉及鱼肉含量的近红外分析模型,其相对分析误差 RPD 都大于 5,根据近红外光谱分析模型的评价标准,RPD 大于 5 表明模型具有较高的精度和良好的稳定性,能够满足实际检测的需求。结果显示,大黄鱼脂肪含量的近红外分析模型具有较高的精度和较好的稳定性,其预测值与标准化学方法

✅ 博主简介:擅长数据搜集与处理、建模仿真、程序设计、仿真代码、论文写作与指导,毕业论文、期刊论文经验交流。
✅ 具体问题可以私信或扫描文章底部二维码。
(1)定标模型的构建是近红外光谱分析技术应用的核心环节,其稳定性与准确性直接决定了分析结果的可靠程度。在水产品的近红外光谱分析中,由于水产品普遍存在高水分含量以及成分复杂的特点,定标模型的构建面临着更多挑战,因此需要结合水产品的特性对模型构建过程进行细致优化。
在模型构建的数理基础方面,需以多元统计分析为依托,综合考虑水产品光谱数据的特殊性。多元线性模型是常用的基础模型之一,在构建过程中,要充分分析水产品中水分、蛋白质、脂肪等多种成分对光谱信号的叠加影响,明确误差的主要来源。其中,水产品的高水分会导致光谱在特定波段出现强吸收,容易掩盖其他成分的特征光谱,这是误差的重要来源之一;此外,样品的形态差异,比如整鱼与鱼糜的物理状态不同,会导致光谱采集时的散射情况存在差异,也会引入误差。针对这些误差来源,需要在模型构建时进行针对性处理,例如通过数据预处理方法削弱水分吸收的干扰,或者通过规范样品采集方式减少形态差异带来的影响。
对于模型精度及有效性的评价,需采用多种统计方法进行综合考量,不能单一依赖某一种指标。均方根误差是常用的指标之一,通过计算预测值与实际值之间的均方根误差,可以直观反映模型的预测精度,在水产品分析中,由于成分含量可能存在较大波动,需结合不同含量范围的均方根误差来评价模型在全量程内的表现。残差分析也具有重要意义,通过对残差的分布特征进行分析,能够判断模型是否存在系统误差,比如残差是否呈现出随样品存储时间或加工方式变化的规律性分布,若存在则需重新审视模型的构建过程,调整相关参数或预处理方法。除了这两种方法,还可引入决定系数等指标,从不同维度全面评估模型的拟合效果,确保构建的定标模型能够适应水产品复杂的特性。
(2)以养殖大黄鱼为研究对象,开展基于近红外光谱分析技术的脂肪含量及鲜度 K 值快速检测模型研究,旨在将该技术应用于鲜活水产品的品质检测中。实验过程中,采用适合现场检测的便携式近红外仪对大黄鱼整鱼进行光谱扫描,为了保证光谱数据的代表性,需选取不同生长阶段、不同养殖环境的大黄鱼样本,每个样本在不同部位进行多次扫描,获取多组光谱数据。同时,采用标准化学方法对样本的粗脂肪含量及鲜度 K 值进行测定,其中粗脂肪含量采用索氏抽提法测定,鲜度 K 值通过高效液相色谱法测定,以此作为模型构建的参考标准值。
光谱预处理是提升模型精度的关键步骤,针对大黄鱼的光谱数据,尝试了多种不同的预处理方式,如平滑处理、基线校正、标准正态变量变换、小波变换等。平滑处理可有效降低光谱数据中的随机噪声,减少因仪器波动对光谱的影响;基线校正能够消除由于样品表面不平整或仪器光学系统差异导致的光谱基线漂移;标准正态变量变换则有助于消除样品颗粒大小、散射程度不同带来的光谱变异;而小波变换在处理大黄鱼光谱数据时表现出独特优势,其细节系数能够快速提取出光谱中与脂肪含量、鲜度 K 值相关的有效信息,过滤掉水分等主要成分带来的冗余信号,显著提升了后续特征波长选择的效率和准确性。
在特征波长选择方面,采用遗传算法对预处理后的光谱数据进行优化。遗传算法通过模拟生物进化过程中的选择、交叉和变异操作,在整个光谱波段中进行全局搜索,能够有效找到与大黄鱼脂肪含量及鲜度 K 值相关的特征波段。与传统的波长选择方法相比,遗传算法避免了陷入局部最优解的问题,所选取出的特征波长更具代表性,减少了无关波长对模型的干扰,为建立高精度的分析模型奠定了基础。
基于筛选出的特征波长,采用偏最小二乘法(PLS)建立大黄鱼脂肪含量及鲜度 K 值的分析模型。结果显示,大黄鱼脂肪含量的近红外分析模型具有较高的精度和较好的稳定性,其预测值与标准化学方法测定值之间的相关性较高,均方根误差较小,能够满足实际检测的需求,可用于养殖大黄鱼脂肪含量的快速无损检测。而鲜度 K 值的分析模型也达到了较高的分析精度,能够实现对大黄鱼鲜度的定量分析,但与脂肪含量的分析模型相比仍有改进空间,后续可通过增加样本数量、优化预处理方法或结合其他算法对模型进行进一步优化,以提升其稳定性和预测精度。
(3)以红娘鱼鱼糜为研究对象,聚焦水产加工制品的近红外快速分析模型研究,探索近红外光谱分析技术在水产加工领域的应用潜力。为了使研究更贴近实际生产和市场情况,模拟市场上流通的鱼糜制品配方、加工过程及贮藏方式制作实验样品。在配方上,按照常见的鱼糜制品配方比例,制作淀粉含量梯度明显的鱼糜制品,淀粉含量从低到高设置多个梯度,同时保证其他成分的比例符合实际生产要求;加工过程中,模拟实际生产中的擂溃、成型、加热等关键步骤;贮藏方式则采用冻藏,并在实验时按照实际流通中的解冻方式进行解冻处理,确保样品的状态与市场上的产品一致。
对处理后的鱼糜制品样品进行近红外光谱扫描,由于鱼糜制品经过加工后形态较为均匀,光谱采集时的一致性较好,但仍需对每个样品进行多次扫描以保证数据的可靠性。在光谱数据预处理阶段,同样尝试了多种方法,如多元散射校正、一阶导数、二阶导数等。多元散射校正能够有效消除鱼糜制品中颗粒散射不均匀带来的光谱差异;一阶导数和二阶导数则可以增强光谱中的特征峰信息,消除基线漂移和背景干扰,通过对比不同预处理方法对模型精度的影响,筛选出最适合红娘鱼鱼糜样品的预处理方式。
采用遗传算法对预处理后的鱼糜制品光谱数据进行波长优化选择,针对鱼糜制品中淀粉及鱼肉含量这两个关键指标,分别筛选出与之相关的特征波长。由于淀粉和鱼肉在近红外光谱区域具有不同的特征吸收峰,遗传算法能够准确识别并提取出这些特征波长,为分别建立淀粉和鱼肉含量的定量模型提供了可靠的输入变量。
基于优化后的波长数据,运用 PLS 方法建立分析鱼糜制品中淀粉及鱼肉含量的定量模型。结果表明,利用同一光谱建立的关于淀粉及鱼肉含量的近红外分析模型,其相对分析误差 RPD 都大于 5,根据近红外光谱分析模型的评价标准,RPD 大于 5 表明模型具有较高的精度和良好的稳定性,能够满足实际检测的需求。这一结果证实了用近红外光谱技术分析鱼糜制品中淀粉及鱼肉含量是切实可行的,而且由于鱼糜制品经过加工后成分分布相对均匀,干扰因素较少,其模型精度好于天然水产样品,充分说明了近红外光谱分析技术在水产加工制品检测中具有显著的应用优势。
此外,在软件实现方面,以 MATLAB 语言和环境为支持,完成了不同光谱数据前处理方式的运算。针对实验中涉及的偏最小二乘算法和遗传算法进行了深入分析和程序编写。偏最小二乘法在实施过程中,通过逐步提取有效信息,能够有效避免光谱模型建立过程中由于变量之间相关性强而导致的多重共线性问题,尤其适用于水产品这种多成分复杂体系的光谱分析;遗传算法凭借其全局搜索能力,在复杂的光谱波段空间中能够进行鲁棒搜索,准确找到与分析指标相关的特征波长,在光谱分析中发挥了重要作用。通过 MATLAB 语言编写相关程序,实现了光谱预处理、特征波长选择以及模型构建等功能,为近红外光谱分析技术在水产品中的应用提供了软件支持。
% 近红外光谱分析水产品相关程序代码
%% 1. 数据导入与初始化
function [spectra, labels, wavelengths] = loadSpectralData(filePath)
% 导入光谱数据和对应标签(如脂肪含量、K值、淀粉含量等)
% 数据格式:每行代表一个样本,前n列为不同波长下的吸光度,最后一列为标签值
data = xlsread(filePath);
spectra = data(:, 1:end-1); % 光谱数据
labels = data(:, end); % 对应的理化指标值
% 导入波长数据(假设波长信息存储在同一文件的第一行)
[~, ~, raw] = xlsread(filePath);
wavelengths = cell2mat(raw(1, 1:end-1)); % 波长值
end
%% 2. 光谱预处理函数集
function processedSpectra = spectralPreprocessing(spectra, method)
% 多种预处理方法选择
switch method
case 'none'
processedSpectra = spectra; % 不预处理
case 'smoothing'
% 移动平均平滑
windowSize = 5; % 窗口大小
[nSamples, nWaves] = size(spectra);
processedSpectra = zeros(nSamples, nWaves);
for i = 1:nSamples
for j = 1:nWaves
startIdx = max(1, j - floor(windowSize/2));
endIdx = min(nWaves, j + floor(windowSize/2));
processedSpectra(i, j) = mean(spectra(i, startIdx:endIdx));
end
end
case 'baselineCorrection'
% 多项式基线校正(采用2次多项式拟合基线)
[nSamples, nWaves] = size(spectra);
processedSpectra = zeros(nSamples, nWaves);
x = 1:nWaves;
for i = 1:nSamples
p = polyfit(x, spectra(i, :), 2); % 拟合基线
baseline = polyval(p, x);
processedSpectra(i, :) = spectra(i, :) - baseline; % 扣除基线
end
case 'snv'
% 标准正态变量变换
[nSamples, nWaves] = size(spectra);
processedSpectra = zeros(nSamples, nWaves);
for i = 1:nSamples
meanVal = mean(spectra(i, :));
stdVal = std(spectra(i, :));
processedSpectra(i, :) = (spectra(i, :) - meanVal) / stdVal;
end
case 'wavelet'
% 小波变换去噪(采用db4小波,分解3层)
[nSamples, nWaves] = size(spectra);
processedSpectra = zeros(nSamples, nWaves);
for i = 1:nSamples
[c, l] = wavedec(spectra(i, :), 3, 'db4'); % 小波分解
% 设置阈值去除噪声(软阈值处理)
thr = wthrmngr('dw1d', 'heursure', c, l);
cD = wrcoef('d', c, l, 'db4', 1:3); % 获取细节系数
cDthr = wthresh(cD, 's', thr); % 对细节系数阈值处理
% 重构光谱
cNew = c;
startIdx = l(1) + 1;
for k = 1:3
endIdx = startIdx + l(k+1) - 1;
cNew(startIdx:endIdx) = cDthr((sum(l(2:k)) + 1):sum(l(2:k+1)));
startIdx = endIdx + 1;
end
processedSpectra(i, :) = waverec(cNew, l, 'db4');
end
case 'msc'
% 多元散射校正
[nSamples, nWaves] = size(spectra);
% 以平均光谱为参考光谱
refSpectra = mean(spectra, 1);
processedSpectra = zeros(nSamples, nWaves);
for i = 1:nSamples
% 线性拟合样本光谱与参考光谱
p = polyfit(refSpectra, spectra(i, :), 1);
% 校正:去除散射影响
processedSpectra(i, :) = (spectra(i, :) - p(2)) / p(1);
end
case 'firstDerivative'
% 一阶导数(差分法)
processedSpectra = diff(spectra, 1, 2);
% 保持与原数据行数一致,补一列0
processedSpectra = [processedSpectra, zeros(size(spectra, 1), 1)];
case 'secondDerivative'
% 二阶导数(差分法)
processedSpectra = diff(spectra, 2, 2);
% 补两列0保持行数
processedSpectra = [processedSpectra, zeros(size(spectra, 1), 2)];
otherwise
error('未定义的预处理方法');
end
end
%% 3. 遗传算法选择特征波长
function [selectedWaves, bestFitness] = gaWavelengthSelection(spectra, labels, popSize, maxGen)
% 输入:预处理后的光谱数据、标签、种群大小、最大迭代次数
% 输出:选中的波长索引、最佳适应度值
nSamples = size(spectra, 1);
nWaves = size(spectra, 2);
if nWaves == 0
error('光谱数据为空,无法进行波长选择');
end
% 定义适应度函数(以PLS模型的交叉验证均方根误差倒数为适应度)
fitnessFcn = @(x) fitnessFunction(x, spectra, labels);
% 遗传算法参数设置
options = gaoptimset('PopulationSize', popSize, ...
'MaxGenerations', maxGen, ...
'EliteCount', round(popSize*0.1), ...
'CrossoverFraction', 0.8, ...
'MutationFcn', @mutationadaptfeasible, ...
'Display', 'iter', ...
'StallGenLimit', 20); % 20代无改进则停止
% 变量范围:二进制变量(0-1),1表示选中该波长
lb = zeros(1, nWaves);
ub = ones(1, nWaves);
intcon = 1:nWaves; % 整数变量(0或1)
% 运行遗传算法
[xBest, fBest] = ga(fitnessFcn, nWaves, [], [], [], [], lb, ub, [], intcon, options);
bestFitness = -fBest; % 还原为实际的适应度(因ga默认最小化,此处取负)
selectedWaves = find(round(xBest) == 1); % 选中的波长索引
end
function fitnessVal = fitnessFunction(x, spectra, labels)
% 适应度函数:计算选中波长下PLS模型的交叉验证RMSE,返回其倒数(值越大越好)
selectedIdx = find(round(x) == 1);
if isempty(selectedIdx) || length(selectedIdx) < 5 % 至少选5个波长
fitnessVal = -Inf; % 惩罚
return;
end
% 提取选中的波长对应的光谱数据
selectedSpectra = spectra(:, selectedIdx);
% 构建PLS模型并进行交叉验证(5折交叉验证)
cv = cvpartition(labels, 'KFold', 5);
rmseCV = 0;
for i = 1:cv.NumTestSets
trainIdx = training(cv, i);
testIdx = test(cv, i);
[plsModel] = plsregress(selectedSpectra(trainIdx, :), labels(trainIdx), 10); % 最多10个潜变量
% 预测测试集
[~, predY] = plsregress(selectedSpectra(trainIdx, :), labels(trainIdx), plsModel.ncomp, selectedSpectra(testIdx, :));
% 计算RMSE
rmseCV = rmseCV + sqrt(mean((predY - labels(testIdx)).^2));
end
rmseCV = rmseCV / cv.NumTestSets;
% 适应度为RMSE的倒数(越小的RMSE对应越大的适应度)
if rmseCV == 0
fitnessVal = Inf;
else
fitnessVal = -rmseCV; % 因ga默认最小化,故取负号
end
end
%% 4. PLS模型构建与评价
function [model, metrics] = plsModelBuilding(trainSpectra, trainLabels, testSpectra, testLabels, nComp)
% 构建PLS模型并计算评价指标
% 训练模型
[plsCoeff, plsLoadings, plsScores, plsT2, plsResiduals] = plsregress(trainSpectra, trainLabels, nComp);
model.coeff = plsCoeff;
model.loadings = plsLoadings;
model.ncomp = nComp;
% 预测训练集和测试集
[~, predTrain] = plsregress(trainSpectra, trainLabels, nComp, trainSpectra);
[~, predTest] = plsregress(trainSpectra, trainLabels, nComp, testSpectra);
% 计算评价指标:RMSE、R²
% 训练集
rmseTrain = sqrt(mean((predTrain - trainLabels).^2));
r2Train = 1 - sum((predTrain - trainLabels).^2) / sum((trainLabels - mean(trainLabels)).^2);
% 测试集
rmseTest = sqrt(mean((predTest - testLabels).^2));
r2Test = 1 - sum((predTest - testLabels).^2) / sum((testLabels - mean(testLabels)).^2);
metrics.rmseTrain = rmseTrain;
metrics.r2Train = r2Train;
metrics.rmseTest = rmseTest;
metrics.r2Test = r2Test;
metrics.predTest = predTest; % 测试集预测值
end
%% 5. 主程序(示例:大黄鱼脂肪含量检测流程)
function main()
% 步骤1:导入数据
[spectra, labels, wavelengths] = loadSpectralData('大黄鱼光谱数据.xlsx');
% 步骤2:划分训练集和测试集(7:3)
cv = cvpartition(labels, 'HoldOut', 0.3);
trainIdx = training(cv);
testIdx = test(cv);
trainSpectraRaw = spectra(trainIdx, :);
trainLabels = labels(trainIdx);
testSpectraRaw = spectra(testIdx, :);
testLabels = labels(testIdx);
% 步骤3:光谱预处理(选择小波变换方法)
trainSpectra = spectralPreprocessing(trainSpectraRaw, 'wavelet');
testSpectra = spectralPreprocessing(testSpectraRaw, 'wavelet'); % 测试集用同样方法预处理
% 步骤4:遗传算法选择特征波长
popSize = 30; % 种群大小
maxGen = 50; % 最大迭代次数
[selectedWaves, ~] = gaWavelengthSelection(trainSpectra, trainLabels, popSize, maxGen);
fprintf('选中的波长索引:%s\n', num2str(selectedWaves));
fprintf('选中的波长值(nm):%s\n', num2str(wavelengths(selectedWaves)));
% 提取选中波长的光谱数据
trainSpectraSel = trainSpectra(:, selectedWaves);
testSpectraSel = testSpectra(:, selectedWaves);
% 步骤5:构建PLS模型(选择合适的潜变量数,此处通过交叉验证确定为8)
nComp = 8;
[model, metrics] = plsModelBuilding(trainSpectraSel, trainLabels, testSpectraSel, testLabels, nComp);
% 输出模型评价结果
fprintf('PLS模型评价结果:\n');
fprintf('训练集RMSE:%.4f,R²:%.4f\n', metrics.rmseTrain, metrics.r2Train);
fprintf('测试集RMSE:%.4f,R²:%.4f\n', metrics.rmseTest, metrics.r2Test);
% 步骤6:可视化预测结果(测试集)
figure;
plot(testLabels, metrics.predTest, 'bo');
hold on;
plot([min(testLabels), max(testLabels)], [min(testLabels), max(testLabels)], 'r--');
xlabel('实际脂肪含量(%)');
ylabel('预测脂肪含量(%)');
title('大黄鱼脂肪含量检测PLS模型预测结果');
grid on;
end

如有问题,可以直接沟通
👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇
更多推荐
所有评论(0)