《sklearn机器学习——数据预处理》非线性转换
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 PowerTransformerX = 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 进行分位数映射(适用于分布未知或复杂情况)
合理使用非线性转换可显著提升模型性能,尤其在数据分布不理想时。始终记得在训练集上拟合变换器,并应用于测试集,避免数据泄露。