一、概念
高度偏斜的特征 : 数据分布不均匀、不对称的特征
处理之后:使其分布更接近正态分布或至少减少偏斜程度
二、处理方法
1、对数变换:log(x)
- 适用于右偏数据
- 压缩大值,拉伸小值
2、平方根变换:sqrt(x)
- 对右偏数据的效果比对数变换温和
3、Box-Cox变换
- 一种更通用的幂变换方法
- 可以处理各种程度的偏斜
4、Yeo-Johnson变换
- Box-Cox的扩展,可以处理负值和零
三、代码
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
from sklearn.preprocessing import PowerTransformer
# 设置随机种子以确保结果可重现
np.random.seed(42)
# 生成一个右偏(正偏)的数据集
data = np.random.lognormal(mean=0, sigma=1, size=10000)
# 计算关键统计量
min_val = np.min(data)
q1 = np.percentile(data, 25)
median = np.median(data)
q3 = np.percentile(data, 75)
max_val = np.max(data)
print(f"原始数据:")
print(f"最小值: {min_val:.2f}")
print(f"25%分位点: {q1:.2f}")
print(f"中位数: {median:.2f}")
print(f"75%分位点: {q3:.2f}")
print(f"最大值: {max_val:.2f}")
print(f"偏度: {stats.skew(data):.2f}")
# 对数变换
log_data = np.log(data)
# 平方根变换
sqrt_data = np.sqrt(data)
# Box-Cox变换
pt_bc = PowerTransformer(method='box-cox')
boxcox_data = pt_bc.fit_transform(data.reshape(-1, 1)).flatten()
# Yeo-Johnson变换
pt_yj = PowerTransformer(method='yeo-johnson')
yeojohnson_data = pt_yj.fit_transform(data.reshape(-1, 1)).flatten()
# 可视化
plt.figure(figsize=(15, 10))
# 原始数据
plt.subplot(231)
plt.hist(data, bins=50, edgecolor='black')
plt.title(u"原始数据分布",fontproperties=zhfont)
plt.xlabel(u'值',fontproperties=zhfont)
plt.ylabel(u"频率",fontproperties=zhfont)
# 对数变换后的数据
plt.subplot(232)
plt.hist(log_data, bins=50, edgecolor='black')
plt.title("对数变换",fontproperties=zhfont)
plt.xlabel("log(值)",fontproperties=zhfont)
plt.ylabel("频率",fontproperties=zhfont)
# 平方根变换后的数据
plt.subplot(233)
plt.hist(sqrt_data, bins=50, edgecolor='black')
plt.title("平方根变换",fontproperties=zhfont)
plt.xlabel("sqrt(值)",fontproperties=zhfont)
plt.ylabel("频率",fontproperties=zhfont)
# Box-Cox变换后的数据
plt.subplot(234)
plt.hist(boxcox_data, bins=50, edgecolor='black')
plt.title("Box-Cox变换",fontproperties=zhfont)
plt.xlabel("Box-Cox(值)",fontproperties=zhfont)
plt.ylabel("频率",fontproperties=zhfont)
# Yeo-Johnson变换后的数据
plt.subplot(235)
plt.hist(yeojohnson_data, bins=50, edgecolor='black')
plt.title("Yeo-Johnson变换",fontproperties=zhfont)
plt.xlabel("Yeo-Johnson(值)",fontproperties=zhfont)
plt.ylabel("频率",fontproperties=zhfont)
plt.tight_layout()
plt.show()
# 计算变换后的统计量
for name, transformed_data in [("对数变换", log_data),
("平方根变换", sqrt_data),
("Box-Cox变换", boxcox_data),
("Yeo-Johnson变换", yeojohnson_data)]:
print(f"\n{name}后:")
print(f"最小值: {np.min(transformed_data):.2f}")
print(f"25%分位点: {np.percentile(transformed_data, 25):.2f}")
print(f"中位数: {np.median(transformed_data):.2f}")
print(f"75%分位点: {np.percentile(transformed_data, 75):.2f}")
print(f"最大值: {np.max(transformed_data):.2f}")
print(f"偏度: {stats.skew(transformed_data):.2f}")
四、结果
原始数据:
最小值: 0.02
25%分位点: 0.51
中位数: 1.00
75%分位点: 1.96
最大值: 50.72
偏度: 5.83
对数变换后:
最小值: -3.92
25%分位点: -0.67
中位数: -0.00
75%分位点: 0.67
最大值: 3.93
偏度: 0.00
平方根变换后:
最小值: 0.14
25%分位点: 0.71
中位数: 1.00
75%分位点: 1.40
最大值: 7.12
偏度: 1.78
Box-Cox变换后:
最小值: -3.91
25%分位点: -0.67
中位数: -0.00
75%分位点: 0.67
最大值: 3.91
偏度: -0.00
Yeo-Johnson变换后:
最小值: -2.18
25%分位点: -0.78
中位数: -0.03
75%分位点: 0.75
最大值: 2.57
偏度: 0.13