基于Python的近红外光谱数据预处理与特征筛选——以哈密瓜品质检测为例

基于Python的近红外光谱数据预处理与特征筛选——以哈密瓜品质检测为例

目录

  • 一、引言
  • 二、研究背景
  • 三、数据集
  • 四、预处理算法
    • (1)原始光谱读取
    • (2)趋势校正(Detrending, DT)
    • (3)标准正态变换(Standard Normal Variate, SNV)
    • (4)多元散射校正(Multiplicative Scatter Correction, MSC)
    • (5)卷积平滑(Savitzky-Golay smoothing, SG)
    • (6)一阶导数(First Derivative, FD)
    • (7)光谱预处理结果
  • 五、特征筛选算法
    • (1)竞争自适应重加权(Competitive Adaptive Reweighted Sampling, CARS)
    • (2)无信息变量消除算法(Uninformative Variables Elimination,UVE)
    • (3)协同区间偏最小二乘算法(Synergisticinterval Partial Least Squares, SiPLS)
    • (4)基于最优预处理方法下的特征筛选结果
  • 六、结论

一、引言

在果蔬内部品质无损检测中,近红外光谱技术(Near-Infrared Spectroscopy, NIRS)因其快速、无损和高效的特点,被广泛用于预测水果的可溶性固形物含量(SSC)、干物质及其他理化指标。然而,受采集条件、样品形态及光学噪声影响,原始光谱往往存在基线漂移、散射效应和噪声干扰等问题,导致模型精度下降。
因此,在建模前需要对光谱进行预处理以消除系统误差,并结合特征波段筛选算法提取有效信息,从而提升模型的稳健性和泛化能力。博主将分享1篇发表在《农业工程学报》(EI)的“哈密瓜可溶性固形物便携式光谱检测装置及通用模型”,以哈密瓜近红外光谱数据为例,介绍如何通过Python实现常见的光谱预处理算法与特征筛选方法,帮助读者快速掌握光谱建模的前期数据处理流程。

论文原文:https://doi.org/10.11975/j.issn.1002-6819.202504261.

欢迎大家交流、引用和分享,博文如需转载请注明来源。

二、研究背景

哈密瓜作为新疆代表性优质甜瓜,其可溶性固形物含量(SSC)是衡量品质和商品价值的重要指标。利用近红外漫透射光谱技术对哈密瓜糖度进行无损检测,可实现快速质量分级与现场检测。然而,由于哈密瓜果皮较厚、内部结构复杂,光谱信号容易受到散射效应、基线漂移以及噪声干扰等因素影响,导致原始光谱中存在大量冗余与无效信息。
为提高模型的稳健性与预测精度,建模前通常需要进行光谱预处理与特征波段筛选。常见的预处理算法包括趋势校正(DT)、标准正态变换(SNV)、多元散射校正(MSC)、卷积平滑(SG)及一阶导数(FD)等,用于消除噪声与光散射影响;而在特征筛选阶段,常采用竞争自适应重加权算法(CARS)、无信息变量消除算法(UVE)及协同区间偏最小二乘算法(SiPLS)等方法,以提取与糖度变化最相关的波长区间,从而为后续模型的构建奠定基础。

三、数据集

本研究使用海洋光学公司生产的QE Pro-FL型号光谱仪采集哈密瓜光谱数据。
部分数据集:通过网盘分享的文件:哈密瓜光谱数据.csv和wave.csv文件。
链接: https://pan.baidu.com/s/1wl1vlf5wLzKT_ME_sNAhPQ 提取码: 2vdu

四、预处理算法

在近红外光谱数据建模过程中,原始光谱往往受到光散射、仪器漂移、噪声和样品表面不均匀性等因素的影响,这会导致光谱信号波动大、信噪比低,从而影响后续模型的稳定性和预测精度。因此,在建模前需要对光谱数据进行合理的预处理。常用的预处理有以下几种。

(1)原始光谱读取

# 原始近红外光谱数据读取与可视化import pandas as pd import numpy as np import matplotlib.pyplot as plt # 设置matplotlib中文显示 plt.rcParams['font.sans-serif']=['SimSun']# 使用宋体 plt.rcParams['axes.unicode_minus']=False# 正常显示负号# 读取数据 X = np.loadtxt('D:/桌面/哈密瓜光谱数据.csv', delimiter=',')# 读取原始光谱数据 wave = np.loadtxt('D:/桌面/wave.csv', delimiter=',')# 读取波长信息# 绘制原始光谱曲线 plt.figure(figsize=(8,5))for spectrum in X: plt.plot(wave, spectrum, linewidth=0.8) plt.title('原始光谱曲线') plt.xlabel('波长 Wavelength (nm)') plt.ylabel('光照强度 Intensity') plt.tight_layout() plt.show()

(2)趋势校正(Detrending, DT)

趋势校正通过去除光谱中的低频漂移或基线变化,使光谱曲线的整体趋势平滑化,从而降低基线漂移对建模的干扰。该方法在处理光谱端点漂移或样品厚度变化引起的光谱偏移时尤为有效。

# 趋势校正from scipy.signal import detrend # 定义去趋势函数defdetrending(input_data): detrended_spectra = detrend(input_data, axis=1)return detrended_spectra # 对所有光谱数据进行去趋势处理 x_dentrended = detrending(X) data5 = x_dentrended.T # 绘制去趋势后的光谱曲线 plt.figure() plt.plot(wave, data5, linewidth=0.8) plt.title('经去趋势变换的光谱曲线') plt.ylabel('光照强度Intensity') plt.xlabel('波长 Wavelength/nm') plt.show()

(3)标准正态变换(Standard Normal Variate, SNV)

SNV是对每个样本的光谱进行均值中心化和标准化处理,将样本的均值归零、标准差归一,从而消除因样品散射或粒径差异造成的光谱强度变化。SNV可以显著提高光谱的可比性,使数据更适合建立回归模型。

# 光谱标准正态变换(SNV)defsnv(data):"""标准正态变换(Standard Normal Variate, SNV)""" mean = np.mean(data, axis=1, keepdims=True) std = np.std(data, axis=1, keepdims=True)return(data - mean)/ std # 对光谱数据进行SNV变换 x_snv = snv(X)# 绘制变换后的光谱曲线 plt.figure(figsize=(8,5)) plt.plot(wave, x_snv.T, linewidth=0.8) plt.title('经SNV变换的光谱曲线') plt.xlabel('波长 Wavelength (nm)') plt.ylabel(光照强度 Intensity') plt.tight_layout() plt.show()

(4)多元散射校正(Multiplicative Scatter Correction, MSC)

MSC通过将每个样本光谱与参考光谱(通常为均值光谱)线性拟合,消除光谱中的散射效应和基线偏移。该方法对样品间因厚度或折射率差异引起的光谱散射非常有效,可以提升模型对样品间差异的鲁棒性。

# 多元散射校正(MSC)defmsc(data, reference=None):"""多元散射校正(Multiplicative Scatter Correction, MSC)"""if reference isNone: reference = np.mean(data, axis=0) corrected = np.zeros_like(data)for i inrange(data.shape[0]): slope, intercept = np.polyfit(reference, data[i,:],1) corrected[i,:]=(data[i,:]- intercept)/ slope return corrected # 对光谱数据进行MSC变换 x_msc = msc(X)# 绘制MSC处理后的光谱曲线 plt.figure(figsize=(8,5)) plt.plot(wave, x_msc.T, linewidth=0.8) plt.title('经MSC变换的光谱曲线') plt.xlabel('波长 Wavelength (nm)') plt.ylabel('光照强度 Intensity') plt.tight_layout() plt.show()

(5)卷积平滑(Savitzky-Golay smoothing, SG)

SG平滑通过局部多项式拟合对光谱进行平滑处理,可以有效去除随机噪声,同时保留光谱的峰形信息。该方法常用于高噪声光谱数据的处理,尤其适合在波长密度较高的情况下增强信号的连续性。

# 光谱卷积平滑(Savitzky-Golay, SG)from scipy.signal import savgol_filter defsg(data, window_length=15, polyorder=2):"""Savitzky-Golay卷积平滑""" smoothed = np.zeros_like(data)for i inrange(data.shape[0]): smoothed[i,:]= savgol_filter(data[i,:], window_length, polyorder, mode='nearest')return smoothed # 对光谱数据进行SG平滑 x_sg = sg(X)# 绘制SG平滑后的光谱曲线 plt.figure(figsize=(8,5)) plt.plot(wave, x_sg.T, linewidth=0.8) plt.title('经SG平滑后的光谱曲线') plt.xlabel('波长 Wavelength (nm)') plt.ylabel('光照强度 Intensity') plt.tight_layout() plt.show()

(6)一阶导数(First Derivative, FD)

一阶导数通过对光谱数据求差分,强化光谱中波峰和波谷的信息,削弱光谱基线漂移和散射影响。该方法常用于突出吸收峰位置和形状特征,从而提高建模对特征波段的敏感性。

# 一阶导数(First Derivative, FD)defspectral_derivative(data, order=1):"""计算光谱数据的一阶或二阶导数""" derivative = np.diff(data, n=order, axis=1)# 为保持样本数一致,在末尾补零列 derivative = np.hstack([derivative, np.zeros((derivative.shape[0],1))])return derivative # 对光谱数据进行一阶导数变换 x_1d = spectral_derivative(X, order=1)# 绘制一阶导数光谱曲线 plt.figure(figsize=(8,5)) plt.plot(wave[:-1], x_1d[:,:-1].T, linewidth=0.8) plt.title('经FD变换的光谱曲线') plt.xlabel('波长 Wavelength (nm)') plt.ylabel('光照强度 Intensity') plt.tight_layout() plt.show()

(7)光谱预处理结果

哈密瓜原始光谱及经多种预处理方法后的光谱可视化结果如下图所示。

在这里插入图片描述

五、特征筛选算法

为了减少光谱端点的噪声干扰并增强有效信号的稳定性,对采集的光谱数据进行了波段截取,仅保留500 ~ 1050 nm区域,再对光谱进行预处理,将预处理后的光谱作为分析对象,从而提高特征提取的可靠性。

(1)竞争自适应重加权(Competitive Adaptive Reweighted Sampling, CARS)

CARS通过多次迭代抽样、PLS回归系数权重评估和指数衰减策略,自动选择与目标变量关系最强的波段。该方法能够有效剔除冗余波段,降低数据维度,同时保持预测性能。

from sklearn.cross_decomposition import PLSRegression from sklearn.model_selection import cross_val_score defCARS(X, y, iteration=50, n_comps=8, cv=10, n_features=100, random_state=42):"""竞争自适应重加权抽样算法 (CARS)""" np.random.seed(random_state) N, D = X.shape prob =0.8 a = np.power((D /2),(1/(iteration -1))) k =(np.log(D /2))/(iteration -1) r =[round(a * np.exp(-(k * i))* D)for i inrange(1, iteration +1)] weights = np.zeros(D)for i inrange(iteration): idCal = np.random.choice(N, size=int(prob * N), replace=False) idW = np.random.choice(D, size=r[i], replace=False) pls = PLSRegression(n_components=min(n_comps,len(idW))) pls.fit(X[idCal][:, idW], y[idCal]) abs_coef = np.abs(pls.coef_).ravel() weights[idW]+= abs_coef / np.sum(abs_coef) selected = np.argsort(weights)[-n_features:]return selected X = X_raw y = Y wave = np.array(wave).ravel()# 确保波长为一维数组 n_comps =8 n_features_list =[275,276,277,278,279] best_r2, best_features =-np.inf,Nonefor n_feat in n_features_list: selected_idx = CARS(X, y, iteration=50, n_comps=n_comps, cv=10, n_features=n_feat) X_sel = X[:, selected_idx] pls = PLSRegression(n_components=min(n_comps, n_feat)) r2 = cross_val_score(pls, X_sel, y, cv=10, scoring="r2").mean()print(f"特征数: {n_feat}, 交叉验证R²: {r2:.4f}")if r2 > best_r2: best_r2, best_features = r2, selected_idx # 输出结果 selected_wavelengths = wave[best_features] X_selected = X[:, best_features]print(f"最佳特征数: {len(best_features)}, 最佳R²: {best_r2:.4f}")print("最佳特征波长 (nm):", selected_wavelengths)

(2)无信息变量消除算法(Uninformative Variables Elimination,UVE)

UVE利用PLS模型系数稳定性对光谱波段进行评估,剔除对目标变量贡献小或不稳定的波段。通过减少无信息变量,可以显著提高模型的稳定性和预测精度。

defUVE(X, y, iteration=50, n_comps=8, cv=3):"""无信息变量消除算法 (UVE)""" N, D = X.shape pls = PLSRegression(n_components=n_comps) pls.fit(X, y) original_coefs = np.abs(pls.coef_).ravel() stability_scores = np.zeros(D)for i inrange(D): X_reduced = np.delete(X, i, axis=1) pls_cv = PLSRegression(n_components=n_comps) cv_scores = cross_val_score(pls_cv, X_reduced, y, cv=cv, scoring='neg_mean_squared_error') stability_scores[i]= np.mean(np.abs(cv_scores)) informative_scores = stability_scores * original_coefs threshold = np.median(informative_scores) informative_vars = np.where(informative_scores >= threshold)[0]return informative_vars W_best = UVE(X, Y) selected_wavelengths = wave[W_best] X_selected = X[:, W_best]print("选择的特征波长:", selected_wavelengths)print("提取后的光谱数据形状:", X_selected.shape)

(3)协同区间偏最小二乘算法(Synergisticinterval Partial Least Squares, SiPLS)

SiPLS将光谱划分为多个连续区间,通过交叉验证评估各区间的贡献,选择表现最佳的波段组合进行建模。该方法不仅能够提取高信息量波段,还可以捕捉不同波段间的协同效应,提高模型预测性能。

defSiPLS(X, Y, interval_length=10):""" 协同区间偏最小二乘算法 (SiPLS) :param X: 光谱数据 (样本数 x 波长数) :param Y: 目标变量 :param interval_length: 每个区间的波长长度 :return: 区间评分和每个区间选择的波长索引 """ n_intervals = X.shape[1]// interval_length scores =[] selected_indices =[]for i inrange(n_intervals): start = i * interval_length end = start + interval_length pls = PLSRegression(n_components=2) score =-np.mean(cross_val_score(pls, X[:, start:end], Y, cv=5, scoring='neg_mean_squared_error')) scores.append(score) selected_indices.append(start)# 保存每个区间的起始波长索引return np.array(scores), np.array(selected_indices, dtype=int) scores, W_best = SiPLS(X, Y) selected_wavelengths = wave[W_best] X_selected = X[:, W_best]print("选择的特征波长:", selected_wavelengths)print("提取后的光谱数据形状:", X_selected.shape)

(4)基于最优预处理方法下的特征筛选结果

为了构建高性能的预测模型,我们对原始数据集进行了一系列最优预处理操作。在此基础上,我们采用了竞争自适应重加权、无信息变量消除算法以及协同区间偏最小二乘算法对其进行特征筛选,筛选的特征波段如下图所示。

在这里插入图片描述


通过上述特征筛选算法,可以将多波段光谱数据转化为关键波段子集,降低建模复杂度,同时提升预测的准确性和稳健性。

六、结论

本文以哈密瓜近红外光谱数据为例,详细介绍了常用的光谱数据处理和特征波段选择方法。具体包括光谱预处理算法:趋势校正(DT)、标准正态变换(SNV)、多元散射校正(MSC)、卷积平滑(SG)以及一阶导数(FD);以及特征筛选算法:竞争自适应重加权抽样(CARS)、无信息变量消除(UVE)和协同区间偏最小二乘(SiPLS)。
通过Python代码实现这些处理步骤,可以有效降低光谱中的噪声和基线漂移,增强信号的稳定性,同时剔除冗余波段,减少多重共线性干扰。这些操作为后续的建模工作(PLS回归、支持向量回归SVR或1D-CNN神经网络)提供了高质量、可靠的输入特征,提高了模型的预测精度和鲁棒性。
此外,这套方法不仅适用于哈密瓜可溶性固形物(SSC)检测,也可以轻松推广到苹果、葡萄、梨、柚子等其他果蔬的品质检测任务中。无论是快速无损检测、产地分级,还是农产品理化指标预测,这些方法都能提供可操作、可复现的技术支持。
总的来说,本文展示的光谱预处理和特征筛选流程,构建了一条从原始光谱采集到关键波段提取的完整路径,既适合科研实验,也能为实际果蔬智能检测和质量控制提供参考,具有较高的应用价值和推广潜力。
如果大家觉得本文对大家的学习和研究有所帮助,请大家关注、点赞和收藏,欢迎转发。谢谢大家!

Read more

Python APP反爬实战:Frida+Charles抓包,破解签名校验

Python APP反爬实战:Frida+Charles抓包,破解签名校验

做爬虫做到APP层面,你会发现网页反爬的那套思路完全失效:用Charles抓包能看到请求参数,但sign/appSign这类签名参数始终是乱码;手动拼接参数模拟请求,服务端直接返回“签名验证失败”;甚至换了代理、改了设备信息,还是过不了服务端的校验——这就是APP反爬的核心壁垒:签名校验。 我经手过电商APP价格爬取、短视频APP数据采集、物流APP轨迹抓取等数十个APP反爬项目,从最初的“抓包改参数被秒拒”,到后来用Frida Hook脱壳获取签名密钥,再到Python还原签名算法实现稳定爬取,踩过的坑能帮新手少走一年弯路。这篇文章全程聚焦“实战”:从APP签名校验的底层逻辑,到Charles抓包定位参数,再到Frida Hook破解签名算法,最后用Python实现完整爬取,每个步骤都附可直接复制的生产级代码,新手也能跟着搞定99%的APP签名反爬。 一、先搞懂:APP签名校验的核心逻辑(为什么普通抓包没用) 新手先别着急装工具,搞懂签名校验的原理,才能精准破解——这是APP反爬的“命门”,也是服务端验证请求合法性的核心手段。 1.1 APP反爬 vs 网页反爬:核心差异

By Ne0inhk
Python 纯函数编程:从理念到实战的完整指南

Python 纯函数编程:从理念到实战的完整指南

Python 纯函数编程:从理念到实战的完整指南 引言:当函数式编程遇见 Python 在我十多年的 Python 开发生涯中,我见证了无数项目因为代码复杂度失控而陷入泥潭。调试时,你永远不知道一个函数会修改哪些全局状态;测试时,你需要费尽心思构造各种环境;并发时,你担心数据竞争导致诡异的 bug。直到我深入理解了纯函数的理念,这一切才豁然开朗。 纯函数(Pure Function)并非 Python 独有的概念,它源自函数式编程范式。但在 Python 这样的多范式语言中,纯函数思想能与面向对象、过程式编程完美融合,帮助我们写出更健壮、更易维护的代码。今天,我想通过实战案例,带你深入理解纯函数的本质,以及它如何让你的 Python 代码脱胎换骨。 一、纯函数的本质:可预测的代码世界 1.1 什么是纯函数? 纯函数必须满足两个核心特征: 特征一:相同输入必定产生相同输出 # 纯函数示例defadd(a,

By Ne0inhk
Python智慧农业信息化服务平台农产品商城系统 小程序

Python智慧农业信息化服务平台农产品商城系统 小程序

文章目录 * 技术架构设计 * 核心功能模块 * 物联网数据整合 * 性能优化策略 * 安全防护措施 * 部署与监控 * 系统设计与实现的思路 * 主要技术与实现手段 * 源码lw获取/同行可拿货,招校园代理 :文章底部获取博主联系方式! 技术架构设计 * 前端框架:采用微信小程序原生框架+WXML/WXSS,结合Vant Weapp组件库快速搭建UI界面。 * 后端服务:基于Django REST Framework构建API,支持JWT身份认证与RBAC权限控制。 * 数据库:MySQL存储业务数据,Redis缓存高频访问数据(如商品详情、用户会话)。 * 消息队列:使用RabbitMQ处理异步任务(如订单状态更新、消息推送)。 核心功能模块 * 用户系统:OpenID自动注册/登录,农户与消费者角色分离,个人中心集成实名认证模块。 * 商品管理:支持多级分类、动态SKU、溯源信息(区块链哈希值存储)。 * 订单系统:微信支付接口对接,物流状态实时同步(调用快递鸟API)。 智能推荐:

By Ne0inhk

Python 爬虫实战:爬取酷狗音乐热门歌曲榜单(附完整源码)

前言 酷狗音乐作为国内主流的音乐平台之一,其热门歌曲榜单汇聚了当下最受用户欢迎的音乐作品,包含歌曲名称、歌手、播放量、评分等丰富信息。掌握酷狗音乐热门榜单的爬取方法,既能帮助音乐爱好者整理心仪的歌曲列表,也能为音乐数据分析提供基础数据源。本文将详细讲解如何使用 Python 爬取酷狗音乐热门歌曲榜单数据,涵盖接口分析、数据请求、JSON 解析、数据存储等核心环节,代码规范可直接运行,适合爬虫初学者系统学习。 摘要 本文以酷狗音乐 TOP500 热门榜单页面(https://www.kugou.com/yy/rank/home/1-8888.html)为爬取目标,通过分析酷狗音乐榜单的 API 接口,使用requests库发送 HTTP 请求获取 JSON 格式的榜单数据,提取歌曲排名、名称、歌手、播放量、时长、评分等核心信息,并将数据存储为 CSV

By Ne0inhk