使用 PLS 回归进行近红外光谱的异常值检测

前言

在光谱数据中,并非每个数据点都是有效的,因此,在构建模型时找到与大部分数据不符合的数据

点是一种必要的操作。这些数据我们称之为异常值。在这篇文章中,我们将使用PLS回归进行红外

光谱数据的异常值检测。

异常值评估


面对冗余繁杂的光谱数据,去除异常值毫无疑问成为一种必要的过程。一个疑问随之而来,我们如

何确定数据是异常值?很多异常样本是无法通过人眼观测的。


从宏观来讲,任何不遵循总体趋势的数据点我们都可以称之为异常点。


我们去一个比较直观的例子,如下图所示,散点图中的数据点。异常值游离于集体之外,模型无法

很好的描述这些数据点。

import numpy as np
import matplotlib.pyplot as plt

# 设置数据的参数
mean = 0
std = 1
num_samples = 100
num_outliers = 5
outlier_value = [10,6,6.4,8,10]

# 生成正常数据
normal_data = np.random.normal(mean, std, num_samples)

# 生成异常数据的索引
outlier_indices = np.random.choice(num_samples, num_outliers, replace=False)

# 将异常值插入到正常数据中
normal_data[outlier_indices] = outlier_value

# 绘制数据
plt.scatter(range(num_samples), normal_data)
plt.xlabel('Sample')
plt.ylabel('Value')
plt.title('Dataset with Outliers')
plt.show()

使用 PLS 回归进行近红外光谱的异常值检测_第1张图片

Q-residuals

Y=U*Q.T+F
Y是响应;
U是原始光谱;
Q是每个波段在最终模型中的权重;
T称为分数,分数可以解释为模型对每个样本描述的重要程度的衡量标准。
E是误差,其中包含模型无法描述的 X 中所有光谱变化。

Q残差由误差矩阵推导而出。Q 残差考虑了模型无法解释的数据变化。


异常值是指不遵循大多数(或所有)点的趋势的点。这意味着对于任何给定模型,与其他点的相应

残差相比,异常值将具有较大的 Q 残差。


在实践中,Q 残差是通过取误差矩阵中每行的平方和来计算的。

Hotelling’s T-squared

T平方是检测异常值的第二个重要指标。Q 残差着眼于模型无法解释的变化,而T平方着眼于模型

本身的变化。模型中样本的好坏由分数来衡量。低分意味着非常适合。T平方可以直观地认为是每

个样本与完美拟合的“理想”零分情况之间的距离。


T平方是通过将分数矩阵的行的平方相加来计算的,然后按其标准差对每行行进行归一化。

计算 Q 残差和 T 平方

ncomp=10
pls = PLSRegression(n_components=ncomp)
# 拟合数据
pls.fit(X2, Y)
 
# X的分数
T = pls.x_scores_
P = pls.x_loadings_
 
# 计算误差数组
Err = X2 - np.dot(T,P.T)
 
# 计算 Q 残差(误差数组行的总和)
Q = np.sum(Err**2, axis=1)
 
# 计算T平方(请注意,默认情况下数据是归一化的)
Tsq = np.sum((pls.x_scores_/np.std(pls.x_scores_, axis=0))**2, axis=1)
# 设置置信度
conf = 0.90
 
from scipy.stats import f
# 计算 T 平方的置信水平
Tsq_conf =  f.ppf(q=conf, dfn=ncomp, \
            dfd=(X2.shape[0]-ncomp))*ncomp*(X2.shape[0]-1)/(X2.shape[0]-ncomp)
 
# 估计 Q 残差的置信水平
i = np.max(Q)+1
while 1-np.sum(Q>i)/np.sum(Q>0)> conf:
    i -= 1
Q_conf = i
ax = plt.figure(figsize=(8,4.5))
with plt.style.context(('Solarize_Light2')):
    plt.plot(Tsq, Q, '*')
 
    plt.plot([Tsq_conf,Tsq_conf],[plt.axis()[2],plt.axis()[3]],  '--')
    plt.plot([plt.axis()[0],plt.axis()[1]],[Q_conf,Q_conf],  '--')
    plt.xlabel("Hotelling's T-squared")
    plt.ylabel('Q residuals')
 
    plt.show()

使用 PLS 回归进行近红外光谱的异常值检测_第2张图片

每个点对应一个样品的光谱。具有较大 Q 残差的点是校准模型无法很好地解释的点。具有较大 T

平方值的点是那些在模型中显示偏差的点。

我们通过考虑交叉验证中的均方误差来估计模型的预测能力。这个想法是一次删除一个异常值,直

至达到最大值,并跟踪均方误差。然后,我们通过找到均方误差的最小值来估计要删除的最佳点

数。

# # RMS距离原点从高到低排序(最大在前)
plscomp=14
 
rms_dist = np.flip(np.argsort(np.sqrt(Q**2+Tsq**2)), axis=0)
 
# 根据降序 RMS 距离对校准光谱进行排序
Xc = X2[rms_dist,:]
Yc = y[rms_dist]
 
# 一次丢弃一个异常值,最多为 max_outliers
# 并计算 PLS 模型的 mse 交叉验证
max_outliers = 7
 
# 定义空 mse 数组
mse = np.zeros(max_outliers)
 
for j in range(max_outliers):
 
    pls = PLSRegression(n_components=plscomp)
    pls.fit(Xc[j:, :], Yc[j:])
    y_cv = cross_val_predict(pls, Xc[j:, :], Yc[j:], cv=5) 
 
    mse[j] = mean_squared_error(Yc[j:], y_cv)
 
    #MSE 中最小值的位置
msemin = np.where(mse==np.min(mse[np.nonzero(mse)]))[0][0]

为了测试代码的性能,让我们比较使用整个数据集构建的 PLS 模型,以及通过排除异常值构建的模型。

下面是包含整个数据集及其参数的模型:

使用 PLS 回归进行近红外光谱的异常值检测_第3张图片

这是在删除异常值之后。

使用 PLS 回归进行近红外光谱的异常值检测_第4张图片

你可能感兴趣的:(回归,算法,机器学习,python,深度学习)