数据预处理方法大全+实战代码(五)--特征工程

前言

数据清洗的第一步:缺失值处理、异常值检测、数据一致性处理,笔者上几篇给出了原理和示例代码,这些也是特征工程里面的内容。
数据和特征决定了算法的上限。,本篇着重讲解特征工程。提到的特征工程和数据预处理是什么关系?特征工程又是什么?

用通俗易懂的话,数据预处理重在数据,确保数据质量,特征工程重在特征选择,特征是从数据中提取的来的,所以两者的关系不可分开。也可以说特征工程依赖于数据预处理。


1、什么是特征工程

一张图说明特征工程有什么

2、数据变换:调整数据的尺度

数据的尺度、分布特性影响模型的选择、性能,最常用的方法:

  • 标准化(Standardization)和归一化(Normalization),适应于比例尺度

  • 类别编码:独热编码/标签编码,适应于名义尺度

数据尺度说的是数据类型和测量级别,分为名义尺度(Nominal Scale),用于分类数据,如性别(男、女);序数尺度(Ordinal Scale),分类之间存在逻辑顺序或等级,如教育程度(小学、中学、大学); 区间尺度(Interval Scale):可以进行加减运算,但不能进行乘除运算,如温度(摄氏度、华氏度);比例尺度(Ratio Scale):可以进行加减乘除运算,如身高、体重等。

数据分布指的是数据点在数值范围内的分布情况,它描述了数据的集中趋势、离散程度和分布形态。均匀分布(Uniform Distribution)正态分布(Normal Distribution)偏态分布(Skewed Distribution)双峰分布(Bimodal Distribution)指数分布(Exponential Distribution)泊松分布(Poisson Distribution)

2.1 标准化(Standardization)

最常见的Z-Score标准化

  • 原理:将数据转换为均值为 0,标准差为 1 的标准正态分布。改变数据范围和数据分布形态。
  • 计算方法
    z = \frac{x - \mu}{\sigma}
    公式说明,x 原始数据,\mu均值,\sigma标准差,z是标准化后的值。
  • 代码
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)  # 标准化 X

RobustScaler标准化

  • 原理:它数据的中位数和四分位数范围(IQR)进行缩放和中心化,对异常值具有更高的鲁棒性,特别适用于包含离群值的数据集。
  • 计算方法
    X_{robust} = \frac{X - \text{median}(X)}{\text{IQR}(X)}
    公式说明,X是原始数据,median(X)是中位数,IQR(X)$是四分位数范围。IQR是四分位距(75th percentile - 25th percentile)。
  • 代码
from sklearn.preprocessing import RobustScaler

scaler = RobustScaler()
X_scaler = scaler.fit_transform(X)  # 标准化 X

2.2 归一化(Normalization)

最小-最大归一化(Min-Max Normalization)

  • 原理:将数据按比例缩放在固定范围内,如 [0, 1] 或 [-1, 1],不改变数据的分布形态。
  • 计算方法
    x' = \frac{x - \min(x)}{\max(x) - \min(x)}

公式说明,x原始数据,min(x)max(x)分别是数据集中的最小值和最大值,x'是归一化后的值。

  • 代码
from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler()
X_normalized = scaler.fit_transform(X)  # 归一化 X
标准化和归一化区别
  • 标准化:适用于数据分布未知或接近正态分布的情况,对于距离计算的算法,如线性回归、SVM等。因为特征的尺度不一样导致某些对模型的影响过大,标准化能确保每个特征对模型有相同的贡献

  • 归一化:适用于数据范围固定且已知的情况,对于数据范围敏感的算法,如KNN、K-Means、神经网络等。归一化有助于加速收敛。


3、数据分布调整

3.1 分位数变换(Quantile Transformation)

  • 原理:将数据的分布转换为均匀分布或正态分布,一种非参数变换方法。
  • 计算方法
    q = \frac{k + 0.5}{n}
    公式说明,k 是数据点在排序后数据集中的位置(从0开始),n 是数据集中的样本总数。分位数 q 可以映射到新的分布上,例如均匀分布U(0, 1)或正态分布N(0, 1)。若目标是均匀分布,直接使用q作为变换后的值;如果目标是正态分布,可以使用标准正态分布的逆累积分布函数 \Phi^{-1}来映射:

x' = \Phi^{-1}(q)
其中,\Phi^{-1} 是标准正态分布的逆CDF。

  • 代码
from sklearn.preprocessing import QuantileTransformer
qt = QuantileTransformer()
X_trans = qt.fit_transform(X) # 分位数变化

3.2 Box-Cox变换

  • 原理:用于将具有正偏态分布的数据转换为近似正态分布,是一种参数化变换方法,。其公式为:

y(\lambda) = \begin{cases} \frac{y^\lambda - 1}{\lambda} & \text{if } \lambda \neq 0 \\ \log(y) & \text{if } \lambda = 0 \end{cases}

公式说明y是原始数据,\lambda是变换参数,需要通过数据来估计。

  • 代码
from sklearn.preprocessing import PowerTransformer
qt = PowerTransformer()
X_trans = qt.fit_transform(X) # 分位数变化

3.2如何使用分位数变换和Box-Cox变换来处理偏斜分布的数据

我准备了一段代码,通过直方图直观地看到如何将原始的偏斜分布转换为更接近正态分布的形式。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.preprocessing import QuantileTransformer, PowerTransformer

# 创建偏斜分布的示例数据
np.random.seed(42)
data = np.random.lognormal(0, 1, 1000).reshape(-1, 1)
df = pd.DataFrame(data, columns=['Feature'])

# 应用分位数变换和Box-Cox变换
quantile_transformer = QuantileTransformer(output_distribution='normal')
power_transformer = PowerTransformer(method='box-cox')

df_quantile = pd.DataFrame(quantile_transformer.fit_transform(df), columns=df.columns)
df_boxcox = pd.DataFrame(power_transformer.fit_transform(df), columns=df.columns)

# 可视化比较
fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(15, 5))

ax1.hist(df, bins=50)
ax1.set_title('Original Data')
ax1.set_xlabel('Value')
ax1.set_ylabel('Frequency')

ax2.hist(df_quantile, bins=50)
ax2.set_title('Quantile Transform')
ax2.set_xlabel('Value')
ax2.set_ylabel('Frequency')

ax3.hist(df_boxcox, bins=50)
ax3.set_title('Box-Cox Transform')
ax3.set_xlabel('Value')
ax3.set_ylabel('Frequency')

plt.tight_layout()
plt.show()
左为原始数据的偏态分布,中为分位数变化,右为Box-Cox变化

参数化变换是假设数据遵循某种特定的分布(如正态分布、指数分布等),并使用该分布的参数(如均值、方差、形状参数等)来描述数据。参数”指的是描述数据分布特征的数值,如均值(μ)和方差(σ²)。

非参数化变换不依赖于对数据分布的特定假设,它直接基于数据的统计特性(如分位数、中位数等)进行变换。

3.2 如何使用对数变换和幂变换来处理偏斜分布的数据

对数变换可以压缩大值之间的差距,而幂变换则可以根据需要调整分布的形状。

df['log_trans'] = np.log1p(df['feature'])  # 对数转换
df['power_trans'] = np.power(df['feature']) # 平方根转换

4、处理类别型特征的方法

目标编码用目标变量的平均值来替换类别,而频数编码则用类别的出现频率来替换类别。

# 目标编码
target_means = train.groupby('Category')['Target'].mean()
train['Target_Encoding'] = train['Category'].map(target_means)
test['Target_Encoding'] = test['Category'].map(target_means)

# 频数编码
frequency = train['Category'].value_counts(normalize=True)
train['Frequency_Encoding'] = train['Category'].map(frequency)
test['Frequency_Encoding'] = test['Category'].map(frequency)

5、多项式特征与交互特征

  • 多项式特征是通过将原始特征进行多项式扩展,如平方、立方等
  • 交互特征是原始特征之间的乘积
  • 优点:帮助捕捉特征之间的非线性关系和交互作用,增加模型的表达能力
  • 缺点:特征数量爆炸,导致过拟合

Scikit-learn提供了 PolynomialFeatures,可以自动生成多项式特征。

# 使用 PolynomialFeatures 生成多项式特征
poly = PolynomialFeatures(degree=2, include_bias=False)
X_poly = poly.fit_transform(X)

# 使用 PolynomialFeatures 生成交互特征
poly = PolynomialFeatures(degree=2, interaction_only=True, include_bias=False)
X_interaction = poly.fit_transform(X)
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容