数据标准化变换示例

在数据建模中,经常需要将数据转换为正态分布,以满足某些算法对数据分布的假设。本文将介绍如何使用Box-Cox和Yeo-Johnson变换,通过PowerTransformer将数据从不同的分布映射到正态分布。此外,还将展示QuantileTransformer的使用,它能够将任意分布的数据转换为高斯分布,前提是有足够的训练样本。

首先,需要注意的是,尽管Box-Cox在对数正态和卡方分布的数据上表现得比Yeo-Johnson更好,但它不支持负值输入。因此,在实际应用中,需要根据数据的特性选择合适的变换方法。

在下面的代码示例中,将生成六种不同概率分布的数据:对数正态、卡方、威布尔、高斯、均匀和双峰分布。然后,将应用Box-Cox和Yeo-Johnson变换,并使用QuantileTransformer进行比较。

import matplotlib.pyplot as plt import numpy as np from sklearn.model_selection import train_test_split from sklearn.preprocessing import PowerTransformer, QuantileTransformer # 设置随机种子以保证结果的可重复性 rng = np.random.RandomState(304) # 初始化变换器 bc = PowerTransformer(method="box-cox") yj = PowerTransformer(method="yeo-johnson") qt = QuantileTransformer(n_quantiles=500, output_distribution="normal", random_state=rng) # 生成不同分布的数据 distributions = { "Lognormal": rng.lognormal(size=(1000, 1)), "Chi-squared": rng.chisquare(df=3, size=(1000, 1)), "Weibull": rng.weibull(a=50, size=(1000, 1)), "Gaussian": rng.normal(loc=100, size=(1000, 1)), "Uniform": rng.uniform(low=0, high=1, size=(1000, 1)), "Bimodal": np.concatenate([rng.normal(loc=100, size=(500, 1)), rng.normal(loc=105, size=(500, 1))], axis=0) } # 创建绘图 fig, axes = plt.subplots(nrows=8, ncols=3, figsize=plt.figaspect(2)) axes = axes.flatten() # 遍历每种分布,应用变换并绘制结果 for i, (name, X) in enumerate(distributions.items()): X_train, X_test = train_test_split(X, test_size=0.5) X_trans_bc = bc.fit(X_train).transform(X_test) X_trans_yj = yj.fit(X_train).transform(X_test) X_trans_qt = qt.fit(X_train).transform(X_test) # 绘制原始数据和变换后的数据 axes[i].hist(X_train, bins=30, color="#D81B60") axes[i].set_title(name, fontsize=6) axes[i].tick_params(axis="both", which="major", labelsize=6) # 绘制Box-Cox变换后的数据 axes[i+6].hist(X_trans_bc, bins=30, color="#0188FF") axes[i+6].set_title(f"After Box-Cox\n$\\lambda$ = {round(bc.lambdas_[0], 2)}", fontsize=6) axes[i+6].tick_params(axis="both", which="major", labelsize=6) # 绘制Yeo-Johnson变换后的数据 axes[i+12].hist(X_trans_yj, bins=30, color="#FFC107") axes[i+12].set_title(f"After Yeo-Johnson\n$\\lambda$ = {round(yj.lambdas_[0], 2)}", fontsize=6) axes[i+12].tick_params(axis="both", which="major", labelsize=6) # 绘制Quantile变换后的数据 axes[i+18].hist(X_trans_qt, bins=30, color="#B7A2FF") axes[i+18].set_title("After Quantile transform", fontsize=6) axes[i+18].tick_params(axis="both", which="major", labelsize=6) plt.tight_layout() plt.show()

在上述代码中,首先导入了必要的库,并设置了随机种子以保证结果的可重复性。然后,初始化了Box-Cox和Yeo-Johnson变换器,以及QuantileTransformer。接下来,生成了六种不同分布的数据,并应用了这些变换。最后,绘制了原始数据和变换后的数据的直方图,以便进行比较。

通过观察这些图表,可以发现,对于某些数据集,变换后的数据确实更接近正态分布。然而,对于其他数据集,变换的效果可能并不理想。这说明在实际应用中,需要根据数据的特性选择合适的变换方法,并通过可视化来评估变换的效果。

此外,还需要注意,QuantileTransformer虽然能够将任意分布的数据转换为高斯分布,但它需要足够的训练样本,并且容易在小数据集上过拟合。因此,在小数据集上,使用PowerTransformer可能是更好的选择。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485