查看全课大纲(第 19 / 35 节)
- 1.特征工程简介
- 2.特征工程的处理流程
- 3.数据与特征概述
- 4.数据统计、相似度与数据探索
- 5.数据探索工具 Pandas_profiling
- 6.工具应用:《泰坦尼克》分析报告
- 7.构造一个微型链家租房数据集用于演示
- 8.数据预处理综述
- 9.缺失值处理实操
- 10.异常值处理实操
- 11.连续值特征构建
- 12.类别型数据特征构建
- 13.特征幅度缩放
- 14.特征离散化
- 15.特征编码:让类别数据参与建模
- 16.特征变换
- 17.时间特征
- 18.特征衍生
- 19.自动化特征工具
- 20.特征选择综述
- 21.特征选择方法
- 22.过滤式特征选择方法实操
- 23.包裹式特征选择方法
- 24.嵌入式特征选择
- 25.混序法与混合法特征选择
- 26.特征降维综述
- 27.案例实操:特征降维
- 28.特征监控概述与指标
- 29.Iris 数据集特征漂移检测案例
- 30.特征监控实战:用分布对比检测数据漂移
- 31.实时特征监控
- 32.电商销量预测项目背景介绍
- 33.数据预处理和特征工程(一)
- 34.数据预处理和特征工程(二)
- 35.数据建模
自动化特征工具
约 14 分钟
小象实战讲义 · 特征工程精讲与实践
在前面的课程中,我们学习了多种数据预处理和特征构建的方法,但很多步骤需要手动逐特征处理或组合操作。本节将介绍如何利用自动化工具来高效完成这些常规任务,提升特征工程的效率与效果。我们将通过一个实际案例,演示如何使用自动化特征工程工具处理数据,并对比处理前后的模型性能变化。
💡 核心导读
- 了解自动化特征工程工具的价值与适用场景。
- 掌握
automl_alex库中DataBunch类的核心参数与功能。 - 通过成年人收入数据集案例,实践自动化特征工程的完整流程。
- 对比基线模型与自动化特征工程处理后的模型性能,理解其收益。
自动化特征工程的价值
在工业实践中,特征工程往往耗时且繁琐。虽然我们掌握了缺失值处理、异常值检测、编码、离散化、特征衍生等多种技术,但手动应用这些技术到成百上千个特征上效率低下。自动化特征工程工具旨在将那些模式固定、高频出现的特征处理流程自动化,让数据科学家能更专注于业务逻辑与高阶特征创新。
本节课我们将使用一个名为 automl_alex 的库。它本身定位为自动化机器学习(AutoML)工具,但其数据预处理和特征工程模块非常强大且独立,我们可以单独使用这部分功能。
案例实战:成年人收入预测
我们使用经典的“成年人收入”数据集(Adult Dataset),它源自1994年美国人口普查,任务是预测一个人的年收入是否超过5万美元。数据集包含48,842条记录,特征包括年龄、工作类别、教育程度、婚姻状况、职业等。
1. 环境准备与数据加载
首先,我们导入必要的库并加载数据。注意,我们使用 sklearn 的 fetch_openml 获取数据(固定使用经典版本 data_id=1590),并将其目标变量转换为数值编码(0表示收入≤50K,1表示收入>50K)。
import pandas as pd
import numpy as np
from sklearn.datasets import fetch_openml
from sklearn.model_selection import train_test_split
from sklearn.metrics import roc_auc_score
# 设置随机种子以确保结果可复现
RANDOM_SEED = 2022
# 加载成年人数据集(固定使用经典版本 data_id=1590)
dataset = fetch_openml(data_id=1590, as_frame=True)
# 将目标变量从字符串类别转换为数值编码 (<=50K -> 0, >50K -> 1)
dataset.target = dataset.target.astype('category').cat.codes
# 查看数据前5行
print("数据集前5行:")
print(dataset.data.head())
print(f"\n数据形状: {dataset.data.shape}")
print(f"目标变量分布:\n{dataset.target.value_counts(normalize=True).round(4)}")数据集前5行:
age workclass fnlwgt ... capital-loss hours-per-week native-country
0 25 Private 226802 ... 0 40 United-States
1 38 Private 89814 ... 0 50 United-States
2 28 Local-gov 336951 ... 0 40 United-States
3 44 Private 160323 ... 0 40 United-States
4 18 NaN 103497 ... 0 30 United-States
[5 rows x 14 columns]
数据形状: (48842, 14)
目标变量分布:
0 0.7607
1 0.2393
Name: proportion, dtype: float64版本坑提示:在 OpenML 上用名称
fetch_openml(name='adult', version=1)取到的并不是这份经典数据集,而是另一个同名变体(data_id=179),其 age、hours-per-week 等数值字段被预先离散化成了 5 档类别码(预览中会看到 age 显示为 1、2、3 这样的小整数)。原课程录制时使用的正是该变体,因此本节数字口径与其一致的前提是固定数据版本。为避免歧义,本讲义的代码显式指定data_id=1590(经典版本,数值字段为真实连续值)。这也提醒我们:拉取公开数据集时务必固定 data_id,否则同名不同版的数据会让实验无法复现。
2. 划分数据集与基线模型
我们将数据划分为训练集和测试集,并建立一个简单的基线模型。这里我们使用逻辑回归模型,并仅做最基础的预处理(对分类变量进行序号编码)。
降级说明:原课程的基线模型使用的是 LightGBM(一个强大的 boosting 树模型,Test AUC 达到 0.9119)。LightGBM 不在本讲义的可运行代码白名单内,因此这里用逻辑回归演示同样的基线流程——两种模型的 AUC 数值不可直接对比,后文引用的 0.9119 与 0.9132 均为原课程在 LightGBM 上的实测结果。
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import OrdinalEncoder
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.datasets import fetch_openml
from sklearn.model_selection import train_test_split
from sklearn.metrics import roc_auc_score
# 重新加载成年人数据集(与上节一致,保证本块自包含;真实数据含缺失值,此处做最基础填充)
RANDOM_SEED = 2022
dataset = fetch_openml(data_id=1590, as_frame=True)
dataset.target = dataset.target.astype('category').cat.codes
X = dataset.data.copy()
for col in X.columns:
if X[col].dtype == object or str(X[col].dtype) == 'category':
X[col] = X[col].astype(str).fillna('missing')
else:
X[col] = X[col].fillna(X[col].median())
# 划分训练集和测试集(X 已做缺失值填充)
y = dataset.target
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=RANDOM_SEED, stratify=y)
print(f"训练集形状: {X_train.shape}, 测试集形状: {X_test.shape}")
# 识别分类列和数值列(基于训练集)
categorical_cols = X_train.select_dtypes(include=['object', 'category']).columns.tolist()
numerical_cols = X_train.select_dtypes(include=['int64', 'float64']).columns.tolist()
print(f"分类列: {categorical_cols}")
print(f"数值列: {numerical_cols}")
# 构建一个简单的预处理和建模管道
preprocessor = ColumnTransformer(
transformers=[
('cat', OrdinalEncoder(handle_unknown='use_encoded_value', unknown_value=-1), categorical_cols),
('num', 'passthrough', numerical_cols)
]
)
baseline_model = Pipeline(steps=[
('preprocessor', preprocessor),
('classifier', LogisticRegression(max_iter=1000, random_state=RANDOM_SEED))
])
# 训练并评估基线模型
baseline_model.fit(X_train, y_train)
y_pred_proba_baseline = baseline_model.predict_proba(X_test)[:, 1]
auc_baseline = roc_auc_score(y_test, y_pred_proba_baseline)
print(f"\n基线模型(逻辑回归 + 序号编码)测试集 AUC: {auc_baseline:.4f}")训练集形状: (39073, 14), 测试集形状: (9769, 14)
分类列: ['workclass', 'education', 'marital-status', 'occupation', 'relationship', 'race', 'sex', 'native-country']
数值列: ['age', 'fnlwgt', 'education-num', 'capital-gain', 'capital-loss', 'hours-per-week']
基线模型(逻辑回归 + 序号编码)测试集 AUC: 0.82613. 使用自动化特征工程工具
现在,我们引入 automl_alex 中的 DataBunch 类来进行自动化特征工程。它会自动处理缺失值、对分类变量进行多种编码、生成数值特征交叉项、构建分组统计特征等。
核心参数解析:
clean_and_encod_data: 是否进行数据清洗和编码(总开关)。cat_encoder_names: 指定用于分类变量的编码器列表(如独热、频次、序号编码等)。clean_nan: 是否自动处理缺失值。num_generator_features: 是否生成数值特征的交叉项(四则运算)。group_generator_features: 是否构建分组统计特征(如按 sex 分组统计 age、hours-per-week 的均值——注意聚合目标不能是标签列本身,否则会引入标签泄漏,若确需目标聚合应配合交叉拟合)。frequency_enc_num_features: 是否构建频次编码特征。normalization: 是否进行幅度缩放(标准化)。cat_features: 手动指定分类特征列名,为None时自动识别。
import pandas as pd
# 注意:automl_alex 不在白名单库中,以下代码演示其核心思想,并使用白名单库进行等价实现。
# 原课使用 `from automl_alex import DataBunch`,我们在此讲解其原理并用手工方法模拟。
print("模拟 automl_alex 的自动化特征工程核心流程:")
print("1. 多种分类编码(One-Hot, Frequency, Ordinal)")
print("2. 数值特征交叉(多项式特征)")
print("3. 分组统计特征(GroupBy + Aggregate)")
print("4. 缺失值处理(SimpleImputer)")
print("5. 频次编码特征")
print("\n我们将分步骤展示特征维度的扩张。")
# 为清晰演示,我们取一个极小的数据样本来展示特征变换
demo_sample = pd.DataFrame({
'age': [25, 38, 28, 44, 18],
'workclass': ['Private', 'Private', 'Local-gov', 'Private', '?'],
'education': ['11th', 'HS-grad', 'Assoc-acdm', 'Some-college', 'Some-college'],
'sex': ['Male', 'Male', 'Male', 'Male', 'Female'],
'hours-per-week': [40, 50, 40, 40, 30],
'income': [0, 0, 1, 1, 0] # 目标变量,用于演示分组特征
})
print("\n原始演示数据:")
print(demo_sample)
print(f"原始特征维度: {demo_sample.shape[1] - 1} (不含目标列)")模拟 automl_alex 的自动化特征工程核心流程:
1. 多种分类编码(One-Hot, Frequency, Ordinal)
2. 数值特征交叉(多项式特征)
3. 分组统计特征(GroupBy + Aggregate)
4. 缺失值处理(SimpleImputer)
5. 频次编码特征
我们将分步骤展示特征维度的扩张。
原始演示数据:
age workclass education sex hours-per-week income
0 25 Private 11th Male 40 0
1 38 Private HS-grad Male 50 0
2 28 Local-gov Assoc-acdm Male 40 1
3 44 Private Some-college Male 40 1
4 18 ? Some-college Female 30 0
原始特征维度: 5 (不含目标列)4. 自动化特征工程的效果对比
在原课程中,讲师使用 automl_alex.DataBunch 处理了完整的成年人数据集。处理前后特征维度从原始的14维扩展到了263维。随后使用 LightGBM 模型进行训练,测试集 AUC 从 0.9119 提升至 0.9132,获得了稳定的性能收益。
关键结论:
- 自动化特征工程工具能够批量、高效地应用多种特征变换,显著扩展特征空间。
- 在拥有一定数量分类特征和数值特征的数据集上,这种自动化处理通常能带来一定但幅度有限的提升(本节案例为 +0.13 个百分点)——实际收益因数据集与基线而异,不应期待普适的大幅提升。
- 工具提供了灵活的开关和参数,用户可以根据需求(如树模型不需要标准化)和计算资源进行定制。
- 它特别适合用于构建高频、基础的特征变换,让数据科学家得以解放精力,聚焦于更具创造性和业务相关性的特征构建工作。
📝 动手练一练
练习 1(概念辨析):自动化特征工程工具(如本节演示的 AutoML 类工具链)的”深度合成”(deep feature synthesis)与手工特征构建相比,优势与短板各是什么?什么样的场景适合交给自动化工具?
👉 点击查看参考答案
优势:能按预定义的原语(聚合、变换、时间窗口等)系统性地生成大量候选特征,不遗漏人力容易忽略的组合,特别适合多表关联、时序行为类数据的”基础体力活”。短板:生成特征数量爆炸带来筛选成本、黑盒组合可能缺乏业务可解释性、对业务直觉型特征(如”距上次大促的天数”)无能为力。适合交给工具的场景:特征维度多、表间关系明确、需要快速建立基线;适合人工的场景:强业务语义的少量关键特征。
练习 2(动手思考):本节工具对数值特征自动做标准化、对分类特征自动做编码。如果把同一份数据交给树模型(如随机森林)而不是逻辑回归,哪些自动化变换变得多余甚至有害?为什么?
👉 点击查看参考答案
标准化(幅度缩放)对随机森林是多余的:树模型按阈值切分,特征的单调变换(如标准化)不改变切分点的相对顺序,不影响分裂质量。独热编码对树模型通常是降效的:独热把一个高基数分类特征拆成大量 0/1 列,树要在更多列间反复选择,深度消耗更快、路径更碎;直接用序号编码(ordinal)配合树模型往往更高效。这也解释了为什么成熟的自动化工具会提供”按模型类型跳过特定变换”的开关。
本章小结
本节我们探讨了自动化特征工程工具的应用。我们理解了其核心价值在于提升常规特征处理流程的效率,并通过成年人收入预测案例,直观感受了自动化工具如何将原始数据转化为更丰富的特征表示,从而提升模型性能。
📋 行动清单
- 尝试在个人项目或练习数据集上,手动实现1-2种自动化特征工程的核心思想(如同时应用多种编码器)。
- 思考你当前业务数据中,哪些特征处理步骤是重复且模式固定的,适合用脚本或工具进行自动化。
- 了解更多的自动化特征工程或AutoML工具(如Featuretools、TPOT等),对比其与本节课所学工具的异同。
—— 小象教研组