使用scikit-learn的PLSRegression时如何解决“ValueError: array must not contain infs or NaNs”错误?

问题背景与现象

在使用scikit-learn的PLSRegression进行偏最小二乘回归分析时,许多开发者会遇到经典的ValueError: array must not contain infs or NaNs错误。这个错误发生在数据矩阵包含无穷大值(inf)缺失值(NaN)时,是机器学习数据预处理阶段的常见痛点。

根本原因分析

PLSRegression作为线性降维算法,其数学基础要求输入矩阵必须满足:

  • 所有元素为有限实数
  • 协方差矩阵可计算
  • 数值在合理范围内

当数据包含以下情况时会触发错误:

  1. 原始数据采集时的传感器故障值
  2. 数据清洗时未处理的缺失值标记
  3. 特征工程中除零错误产生的inf
  4. 数据标准化时的异常极值

系统解决方案

1. 数据检测与诊断

import numpy as np
from sklearn.cross_decomposition import PLSRegression

def check_data(X):
    print(f"NaN count: {np.isnan(X).sum()}")
    print(f"Inf count: {np.isinf(X).sum()}")
    print(f"Zero count: {(X == 0).sum()}")

2. 缺失值处理策略

方法 适用场景 实现代码
均值填充 正态分布数据 X[np.isnan(X)] = np.nanmean(X)
中位数填充 存在离群值 X[np.isnan(X)] = np.nanmedian(X)

3. 无穷值处理方法

对于inf值的处理需要结合业务场景:

  • 替换为极值:X[np.isinf(X)] = np.finfo('float64').max
  • 使用插值法:from scipy.interpolate import interp1d
  • 整行删除(当缺失比例高时):X = X[~np.isinf(X).any(axis=1)]

进阶优化建议

针对高维数据推荐以下增强方案:

  1. 使用Pipeline封装预处理
    from sklearn.pipeline import make_pipeline
    from sklearn.impute import SimpleImputer
    
    pls_pipe = make_pipeline(
        SimpleImputer(strategy='median'),
        PLSRegression(n_components=2)
    )
  2. 结合KNNImputer处理非线性关系
    from sklearn.impute import KNNImputer
    imputer = KNNImputer(n_neighbors=5)

性能比较与选择

不同处理方式对模型R²得分的影响:

不同缺失值处理方法性能对比

最佳实践示例

# 完整解决方案
import numpy as np
from sklearn.datasets import make_regression
from sklearn.model_selection import train_test_split
from sklearn.cross_decomposition import PLSRegression
from sklearn.impute import SimpleImputer

# 生成含5%缺失值的模拟数据
X, y = make_regression(n_samples=1000, n_features=20, random_state=42)
X.ravel()[np.random.choice(X.size, int(0.05*X.size), replace=False)] = np.nan

# 构建鲁棒处理管道
model = make_pipeline(
    SimpleImputer(strategy='median'),
    PLSRegression(n_components=5)
)

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)
model.fit(X_train, y_train)
print(f"Test R²: {model.score(X_test, y_test):.3f}")