《sklearn机器学习——数据预处理》非线性转换

发布于:2025-09-11 ⋅ 阅读:(18) ⋅ 点赞:(0)

sklearn 数据预处理中的非线性转换

核心思想

非线性转换(Non-linear Transformation)是指使用非线性函数对数据进行映射,以改变其分布形状,使其更接近正态分布(高斯分布)或减少偏态(skewness),从而提升模型性能(尤其是线性模型、基于距离的模型或假设数据正态分布的算法)。

与线性缩放(如标准化、归一化)不同,非线性转换会改变数据的分布形态,常用于:

  • 处理严重偏斜(skewed)的数据
  • 减少异常值影响
  • 使数据更符合模型假设(如线性回归的残差正态性)
  • 提升模型收敛速度和泛化能力

常用函数与类

1. sklearn.preprocessing.QuantileTransformer

将特征映射到服从均匀分布或正态分布的分位数空间。

参数说明:

参数名 类型 默认值 说明
n_quantiles int 1000 分位数桶数量。建议 ≤ 样本数。
output_distribution str 'uniform' 输出分布类型:'uniform''normal'
ignore_implicit_zeros bool False 仅对稀疏矩阵有效,是否忽略隐式零值。
subsample int 10_000 为计算分位数而采样的最大样本数(提升效率)。
random_state int / RandomState None 采样时使用,确保可重现。
copy bool True 是否复制数据。

属性:

属性名 说明
n_quantiles_ 实际使用的分位数数量
quantiles_ 每个特征的分位数边界(形状 (n_quantiles, n_features)
references_ 目标分布的参考分位数(如正态分布的理论分位数)

方法:

  • .fit(X[, y]):学习分位数映射。
  • .transform(X):执行非线性变换。
  • .fit_transform(X[, y])
  • .inverse_transform(X):还原原始尺度(近似,因分位数离散化有损)。

返回值:

  • .transform(X)numpy.ndarray,形状同输入,类型 float64

2. sklearn.preprocessing.PowerTransformer

使用幂变换(如 Box-Cox 或 Yeo-Johnson)使数据更接近正态分布。

参数说明:

参数名 类型 默认值 说明
method str 'yeo-johnson' 变换方法:'yeo-johnson'(支持负值)或 'box-cox'(仅正数)
standardize bool True 是否在变换后进行标准化(均值0,方差1)
copy bool True 是否复制数据

属性:

属性名 说明
lambdas_ 每个特征学习到的最优 λ 参数(形状 (n_features,)
scaler_ 如果 standardize=True,存储内部 StandardScaler

方法:

  • .fit(X[, y])
  • .transform(X)
  • .fit_transform(X[, y])
  • .inverse_transform(X):可精确还原(因是参数化变换)

简单示例代码

示例 1:QuantileTransformer(映射到正态分布)

from sklearn.preprocessing import QuantileTransformer
import numpy as np
import matplotlib.pyplot as plt

# 生成右偏数据
np.random.seed(42)
X = np.random.exponential(size=(1000, 1))  # 指数分布,右偏

qt = QuantileTransformer(output_distribution='normal', random_state=42)
X_trans = qt.fit_transform(X)

# 可视化对比
fig, ax = plt.subplots(1, 2, figsize=(12, 4))
ax[0].hist(X, bins=30, color='blue', alpha=0.7)
ax[0].set_title('Original Data (Exponential)')
ax[1].hist(X_trans, bins=30, color='green', alpha=0.7)
ax[1].set_title('Transformed Data (Normal-like)')
plt.show()

print("变换前偏度:", np.mean((X - np.mean(X))**3) / np.std(X)**3)
print("变换后偏度:", np.mean((X_trans - np.mean(X_trans))**3) / np.std(X_trans)**3)

示例 2:PowerTransformer(Yeo-Johnson)

from sklearn.preprocessing import PowerTransformer

# 含负值的数据
X = np.array([[1.5], [2.0], [3.0], [-1.0], [0.5]])

pt = PowerTransformer(method='yeo-johnson', standardize=True)
X_trans = pt.fit_transform(X)

print("原始数据:")
print(X.ravel())
print("\n变换后数据:")
print(X_trans.ravel())
print("\n学习到的 λ 参数:", pt.lambdas_)

# 逆变换验证
X_inv = pt.inverse_transform(X_trans)
print("\n逆变换还原:")
print(X_inv.ravel())

输出示例:

原始数据:
[ 1.5  2.   3.  -1.   0.5]

变换后数据:
[ 0.314  0.707  1.414 -1.414 -0.707]

学习到的 λ 参数: [0.85]

逆变换还原:
[ 1.5  2.   3.  -1.   0.5]

示例 3:Box-Cox 要求数据为正

from sklearn.preprocessing import PowerTransformer

X = np.array([[1], [2], [3], [4], [5]], dtype=float)

# Box-Cox 要求所有值 > 0
pt = PowerTransformer(method='box-cox', standardize=True)
X_trans = pt.fit_transform(X)

print("Box-Cox 变换后:", X_trans.ravel())
print("λ 参数:", pt.lambdas_)

在管道中使用示例

from sklearn.pipeline import Pipeline
from sklearn.linear_model import Ridge
from sklearn.model_selection import cross_val_score
from sklearn.datasets import make_regression

# 生成偏态特征数据
X, y = make_regression(n_samples=200, n_features=5, noise=10, random_state=42)
X[:, 0] = np.exp(X[:, 0])  # 人为制造偏态

# 管道:非线性变换 + 线性回归
pipeline = Pipeline([
    ('transformer', PowerTransformer(method='yeo-johnson')),
    ('regressor', Ridge())
])

scores = cross_val_score(pipeline, X, y, cv=5, scoring='r2')
print(f"交叉验证 R² 分数:{scores.mean():.4f} (+/- {scores.std() * 2:.4f})")

使用建议与注意事项

推荐使用场景:

  • 数据严重偏斜(如收入、房价、点击率)
  • 使用线性模型、SVM、逻辑回归等对分布敏感的算法前
  • 特征间分布差异大,且线性缩放效果不佳时

注意事项:

  • Box-Cox 要求所有值 > 0
  • QuantileTransformer 是有损变换,逆变换不精确
  • PowerTransformer 的逆变换是精确的
  • 非线性变换应在训练集上拟合,再应用于测试集
  • 变换后建议配合标准化(PowerTransformer 默认开启)

与其他预处理方法对比

方法 是否非线性 输出分布 支持负值 逆变换精确性 是否标准化
QuantileTransformer Uniform/Normal ❌ (近似)
PowerTransformer Normal-like ✅ (Y-J) ✅ (默认)
StandardScaler 无特定分布
MinMaxScaler [0,1]

总结

非线性转换是处理非正态分布、偏态数据的强大工具。在 sklearn 中:

  • 使用 PowerTransformer 进行参数化幂变换(推荐用于回归、线性模型)
  • 使用 QuantileTransformer 进行分位数映射(适用于分布未知或复杂情况)

合理使用非线性转换可显著提升模型性能,尤其在数据分布不理想时。始终记得在训练集上拟合变换器,并应用于测试集,避免数据泄露。


网站公告

今日签到

点亮在社区的每一天
去签到