📊 模块3:"缩放、选择和特征提取:准备输入的艺术"

目标:

掌握如何转换、选择和创建特征,使模型高效、稳定地学习且无数值偏差。了解为什么并非所有变量都有用——以及如何让有用的变量发挥作用。


3.1 为什么要缩放特征?

许多机器学习算法(SVM、KNN、逻辑回归、神经网络)对特征尺度敏感。

想象一下:

  • 特征1:年龄 → 范围18到90
  • 特征2:年收入 → 范围20,000到500,000

如果不进行缩放,算法会仅仅因为数字较大而给年收入分配更多权重——即使年龄更具预测性!


3.2 缩放方法

➤ StandardScaler(标准化)

转换数据使其均值=0标准差=1

from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()
df[['年龄', '年收入']] = scaler.fit_transform(df[['年龄', '年收入']])

使用时机: 当数据近似遵循正态分布时。适合线性模型、SVM、神经网络。


➤ MinMaxScaler(归一化)

将数据转换为固定范围,通常是[0, 1]。

from sklearn.preprocessing import MinMaxScaler

scaler = MinMaxScaler()
df[['交易金额', '客户资历']] = scaler.fit_transform(df[['交易金额', '客户资历']])

使用时机: 当您知道最小/最大边界时,或使用具有sigmoid或tanh激活函数的神经网络时。

⚠️ 注意异常值: 单个极值可以压缩整个其余范围。


➤ RobustScaler

使用中位数四分位距(IQR)。对异常值鲁棒。

from sklearn.preprocessing import RobustScaler

scaler = RobustScaler()
df[['交易金额']] = scaler.fit_transform(df[['交易金额']])

使用时机: 当您有许多异常值且不想删除或转换它们时。


📈 可视化:比较缩放

import matplotlib.pyplot as plt
import seaborn as sns

# 原始数据
original = df_original['交易金额'].values.reshape(-1, 1)
standard_scaled = StandardScaler().fit_transform(original)
minmax_scaled = MinMaxScaler().fit_transform(original)
robust_scaled = RobustScaler().fit_transform(original)

fig, ax = plt.subplots(2, 2, figsize=(12, 8))

sns.histplot(original, bins=30, ax=ax[0,0], kde=True)
ax[0,0].set_title("原始")

sns.histplot(standard_scaled, bins=30, ax=ax[0,1], kde=True)
ax[0,1].set_title("StandardScaler")

sns.histplot(minmax_scaled, bins=30, ax=ax[1,0], kde=True)
ax[1,0].set_title("MinMaxScaler")

sns.histplot(robust_scaled, bins=30, ax=ax[1,1], kde=True)
ax[1,1].set_title("RobustScaler")

plt.tight_layout()
plt.show()

3.3 特征选择

并非所有变量都有用。有些是冗余的、无关的或有噪声的。保留它们:

  • 增加训练时间。
  • 可能导致过拟合。
  • 使解释更困难。

➤ 基于方差的消除

如果变量几乎不变化(例如,99%的值为0),它不提供信息。

from sklearn.feature_selection import VarianceThreshold

selector = VarianceThreshold(threshold=0.01)  # 移除方差<0.01的列
X_high_variance = selector.fit_transform(X)

➤ 单变量选择

使用统计测试来衡量每个特征与目标变量之间的关系。

from sklearn.feature_selection import SelectKBest, f_classif

# 使用ANOVA F-test选择前10个特征
selector = SelectKBest(score_func=f_classif, k=10)
X_selected = selector.fit_transform(X, y)

# 查看分数
scores = selector.scores_
feature_names = X.columns
plt.figure(figsize=(10,6))
sns.barplot(x=scores, y=feature_names)
plt.title("特征重要性(ANOVA F-test)")
plt.show()

➤ 递归特征消除(RFE)

训练模型并迭代移除最不重要的特征。

from sklearn.feature_selection import RFE
from sklearn.ensemble import RandomForestClassifier

base_model = RandomForestClassifier(n_estimators=10, random_state=42)
rfe = RFE(estimator=base_model, n_features_to_select=8)
X_rfe = rfe.fit_transform(X, y)

# 查看选中的特征
selected_features = X.columns[rfe.support_]
print("选中的特征:", selected_features.tolist())

3.4 特征提取

不是选择,而是从现有特征创建新特征

➤ 主成分(PCA)

通过将原始变量转换为较少的不相关变量(主成分)来降低维度。

from sklearn.decomposition import PCA

pca = PCA(n_components=5)  # 减少到5个成分
X_pca = pca.fit_transform(X_scaled)

# 查看每个成分解释的方差
plt.figure(figsize=(8,5))
plt.plot(range(1,6), pca.explained_variance_ratio_.cumsum(), marker='o')
plt.title("PCA成分解释的累积方差")
plt.xlabel("成分数")
plt.ylabel("累积方差")
plt.grid()
plt.show()

使用时机: 当您有许多相关变量时,或用于可视化(减少到2D/3D)。

⚠️ 缺点: 失去可解释性。"成分1"没有明确的业务含义。


📝 练习3.1:转换和特征选择

数据集: 欺诈_编码.csv(来自上一模块,已编码)

任务:

  1. 将特征(X)与目标变量(y = 是否欺诈)分离。
  2. 分割为训练/测试集(80/20,分层=y)。
  3. 对连续数值变量(如年龄收入金额)应用StandardScaler
  4. 使用VarianceThreshold移除方差<0.01的特征。
  5. 使用SelectKBestf_classif选择12个最相关的特征。
  6. 使用选中的特征训练简单模型(逻辑回归)。
  7. 与在所有特征上训练的模型(无选择)比较性能(准确性)。

💡 附加说明:

  • 总是只对训练集应用缩放,然后在测试集上使用transform()(不是fit_transform())。
  • 特征选择必须在交叉验证内完成以避免过于乐观的指标。
  • PCA不是魔法。 如果您的变量已经很少且不相关,PCA可能恶化性能。
  • 在Kaggle竞赛中,特征工程通常将前10%与其他参赛者区分开来。

Course Info

Course: AI-course1

Language: ZH

Lesson: Module3