【大模型】大模型学习总结之机器学习 -2.机器学的特征工程
机器学习的特征工程

1、 什么是特征工程
特征工程是从原始数据中提取、转换、选择最有效特征的过程。本质是将业务知识、领域洞察转化为机器可理解的数值表达。
- 核心本质:数据预处理 + 领域知识建模 + 模型能力适配的桥梁
- 关键认知:
- 特征决定模型上限,算法只负责逼近这个上限
- 好的特征让简单模型表现优异,坏的特征让复杂模型徒劳无功
- 是"数据科学中最依赖人类智能"的环节
2、 特征工程都有哪些内容
| 维度 | 核心内容 | 价值 |
|---|---|---|
| 数据理解 | 探索性分析(EDA)、缺失值/异常值检测、分布分析 | 建立数据全景认知 |
| 特征构造 | 基础统计量、交互特征、时序特征、文本/图像特征转化 | 创造新的预测信号 |
| 特征转换 | 归一化/标准化、非线性变换(对数/box-cox)、编码处理 | 适配模型假设 |
| 特征选择 | 过滤法(filter)、包裹法(wrapper)、嵌入法(embedded) | 去冗余、降维度 |
| 特征评估 | 重要性排序、稳定性分析、业务解释性验证 | 确保特征质量 |
| 特征降维 | 主成分分析(PCA)、线性判别分析(LDA)、(4)自编码器(Auto Encoder) | 压缩实现数据 |
3、 特征工程常用的方法
3.1 数据清洗与处理
缺失值处理:删除、均值/中位数填充、KNN填充、预测模型填充
异常值处理:3σ原则、IQR箱线图、截断/替换
数据类型转换:数值型、类别型、时序型、文本型转换
3.2 特征构造方法
- 统计特征:均值、方差、偏度、峰度、分位数
- 交互特征:特征相乘/相除、多项式特征
- 时序特征:时间差、周期性(星期/月份)、滚动窗口统计
- 领域特征:
- NLP:TF-IDF、Word2Vec、BERT embedding
- CV:SIFT、HOG、CNN特征提取
- 用户行为:RFM模型、留存率、活跃度
3.3 特征转换方法
- 数值型:
- Min-Max标准化:X’ = (X - min)/(max - min)
- Z-score标准化:X’ = (X - μ)/σ
- 对数变换:log(X + 1) 处理偏态分布
- 类别型:
- 标签编码(Label Encoding)
- 独热编码(One-Hot Encoding)
- 目标编码(Target Encoding)
- 哈希编码(Hashing Encoding)
3.4 特征选择方法
- 过滤法:相关系数、卡方检验、互信息、方差阈值
- 包裹法:递归特征消除(RFE)、前向选择
- 嵌入法:L1正则(Lasso)、树模型特征重要性、XGBoost/LightGBM的gain/cover
4、 特征工程demo
以房价预测为例,展示完整特征工程流程:
场景背景:假设我们有一个房价预测任务,原始数据包含了房屋的基本信息(面积、房间数、房龄、位置、风格)和售价。
Demo要解决的问题:
原始数据通常存在以下问题,不能直接喂给模型:
数据不完整(有缺失值)
特征信息利用率低(仅使用原始字段)
数值范围差异大(面积几千,房间数个位)
类别特征无法计算(位置、风格是文本)
特征可能冗余(有些特征对预测无用)
import pandas as pd
import numpy as np
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.feature_selection import SelectKBest, f_regression
from sklearn.ensemble import RandomForestRegressor
# ===== 1. 数据加载与探索 =====
data = pd.read_csv('housing.csv')
print("原始数据形状:", data.shape)
print(data.describe())
print("缺失值统计:\n", data.isnull().sum())
# ===== 2. 缺失值处理 =====
# 数值型用中位数填充
num_cols = ['area', 'rooms', 'age']
for col in num_cols:
data[col].fillna(data[col].median(), inplace=True)
# 类别型用众数填充
cat_cols = ['location', 'style']
for col in cat_cols:
data[col].fillna(data[col].mode()[0], inplace=True)
# ===== 3. 特征构造 =====
# 构造交互特征
data['area_per_room'] = data['area'] / data['rooms']
data['age_category'] = pd.cut(data['age'],
bins=[0, 5, 15, 100],
labels=['new', 'mid', 'old'])
# 构造统计特征
data['price_per_area'] = data['price'] / data['area']
# ===== 4. 特征编码 =====
# 独热编码
encoder = OneHotEncoder(drop='first', sparse=False)
cat_encoded = encoder.fit_transform(data[['location', 'style']])
cat_feature_names = encoder.get_feature_names_out(['location', 'style'])
# 合并编码特征
num_features = data[['area', 'rooms', 'age', 'area_per_room']].values
X = np.hstack([num_features, cat_encoded])
y = data['price'].values
# ===== 5. 特征标准化 =====
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
# ===== 6. 特征选择 =====
# 使用F回归选择Top 10特征
selector = SelectKBest(score_func=f_regression, k=10)
X_selected = selector.fit_transform(X_scaled, y)
# 获取选中的特征名称
selected_indices = selector.get_support(indices=True)
feature_names = list(num_cols + ['area_per_room'] + list(cat_feature_names))
selected_features = [feature_names[i] for i in selected_indices]
print("选中特征:", selected_features)
# ===== 7. 特征重要性评估 =====
rf = RandomForestRegressor(n_estimators=100, random_state=42)
rf.fit(X_selected, y)
importance = rf.feature_importances_
feature_importance_df = pd.DataFrame({
'feature': selected_features,
'importance': importance
}).sort_values('importance', ascending=False)
print("\n特征重要性排序:")
print(feature_importance_df)
输出示例:
选中特征: ['area', 'area_per_room', 'location_市中心', 'age', 'rooms', 'style_现代', 'location_近郊', 'location_学区', 'age_category_mid', 'style_欧式']
特征重要性排序:
feature importance
0 area 0.3521
1 area_per_room 0.2134
2 location_市中心 0.1567
3 age 0.1089
4 rooms 0.0675
5 style_现代 0.0456
...
代码分段解析
===== 第1步:数据加载与探索 =====
import pandas as pd
import numpy as np
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.feature_selection import SelectKBest, f_regression
from sklearn.ensemble import RandomForestRegressor
# 读取原始数据
data = pd.read_csv('housing.csv')
print("原始数据形状:", data.shape)
print(data.describe())
print("缺失值统计:\n", data.isnull().sum())
解释说明:
- 目的:拿到原始数据,先看看数据长什么样
- 原始数据示例:
| area | rooms | age | location | style | price |
|---|---|---|---|---|---|
| 120 | 3 | 10 | 市中心 | 现代 | 500万 |
| 80 | 2 | NaN | 近郊 | 中式 | 300万 |
- data.isnull().sum():统计每列有多少空值,比如age列可能有5个缺失值
- 这一步的意义:知己知彼,了解数据质量,为后续处理做准备
===== 第2步:缺失值处理 =====
# 数值型用中位数填充
num_cols = ['area', 'rooms', 'age']
for col in num_cols:
data[col].fillna(data[col].median(), inplace=True)
# 类别型用众数填充
cat_cols = ['location', 'style']
for col in cat_cols:
data[col].fillna(data[col].mode()[0], inplace=True)
解释说明:
-
问题:原始数据中有空值,比如某套房子的age(房龄)未知
-
为什么用中位数:中位数不受极端值影响,比如房龄大部分在10-20年,个别有100年的老房,中位数能代表"典型情况"
-
为什么用众数:location是类别型(市中心/近郊/学区),不能计算平均,用出现最多的值填充最合理
-
处理示例:
处理前:area rooms age location 120 3 NaN 市中心 处理后:area rooms age location 120 3 15 市中心
===== 第3步:特征构造 =====
# 构造交互特征
data['area_per_room'] = data['area'] / data['rooms']
data['age_category'] = pd.cut(data['age'],
bins=[0, 5, 15, 100],
labels=['new', 'mid', 'old'])
# 构造统计特征
data['price_per_area'] = data['price'] / data['area']
解释说明:
-
这是特征工程的核心——创造新特征!
-
特征1:area_per_room(人均面积)
- 为什么:同样120平的房子,3室和2室的"宽敞程度"完全不同
- 原始信息:只给了总面积和房间数
- 新特征:120/3=40(每间房40平),80/2=40(每间房40平),虽然面积不同,但居住体验可能相近
-
特征2:age_category(房龄分类)
- 为什么:房龄是连续值(0-100年),模型可能难以捕捉"新、中、老"的跳跃性差异
- 分类规则:
- 0-5年 → new(新房)
- 5-15年 → mid(次新房)
- 15年以上 → old(老房)
-
特征3:price_per_area(单价)
- 为什么:这是目标衍生特征,可用于特征重要性评估或业务分析
-
构造前后对比:
原始特征:area rooms age 120 3 10 80 2 4 新增特征:
area_per_room age_category 40 mid 40 new
===== 第4步:特征编码 =====
# 独热编码
encoder = OneHotEncoder(drop='first', sparse=False)
cat_encoded = encoder.fit_transform(data[['location', 'style']])
cat_feature_names = encoder.get_feature_names_out(['location', 'style'])
# 合并编码特征
num_features = data[['area', 'rooms', 'age', 'area_per_room']].values
X = np.hstack([num_features, cat_encoded])
y = data['price'].values
解释说明:
- 问题:机器学习模型只能处理数字,不能直接计算"市中心"、"中式"这些文本
- 解决方案:独热编码(One-Hot Encoding),把类别转成二进制向量
- 编码示例:
原始类别数据:
| location | style |
|---|---|
| 市中心 | 现代 |
| 近郊 | 中式 |
| 学区 | 现代 |
独热编码后:
| location_近郊 | location_学区 | location_市中心 | style_中式 | style_现代 |
|---|---|---|---|---|
| 0 | 0 | 1 | 0 | 1 |
| 1 | 0 | 0 | 1 | 0 |
| 0 | 1 | 0 | 0 | 1 |
- 关键点:
- drop=‘first’:去掉第一个类别(避免完全共线性,比如"location_市中心"为0时,自动表示其他位置)
- sparse=False:返回稠密矩阵,方便后续合并
- np.hstack:将数值特征和编码特征横向拼接成完整特征矩阵
X = [
[area, rooms, age, area_per_room, location_近郊, location_学区, location_市中心, style_中式, style_现代],
[120, 3, 10, 40, 0, 0, 1, 0, 1],
[80, 2, 4, 40, 1, 0, 0, 1, 0],
...
]
===== 第5步:特征标准化 =====
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
解释说明:
-
问题:特征之间量纲差异大,影响模型收敛
- area范围:50-500(几百)
- rooms范围:1-10(个位)
- area_per_room范围:10-100(两位数)
- 独热编码特征:0或1
-
标准化公式:X’ = (X - μ) / σ
- μ:均值
- σ:标准差
-
标准化示例:
标准化前:
area rooms location_市中心 120 3 1 80 2 0 标准化后(假设):
area rooms location_市中心 1.2 0.5 1.0 -0.8 -1.5 -1.0
现在所有特征都在相近的数值范围内,模型训练更稳定
===== 第6步:特征选择 =====
# 使用F回归选择Top 10特征
selector = SelectKBest(score_func=f_regression, k=10)
X_selected = selector.fit_transform(X_scaled, y)
# 获取选中的特征名称
selected_indices = selector.get_support(indices=True)
feature_names = list(num_cols + ['area_per_room'] + list(cat_feature_names))
selected_features = [feature_names[i] for i in selected_indices]
print("选中特征:", selected_features)
解释说明:
-
问题:可能构造了太多特征(比如有50个),其中有些对房价预测没有帮助,反而增加计算成本和过拟合风险
-
解决方案:特征选择,保留最有用的特征
-
F回归原理:
- 计算每个特征与目标变量(房价)的F统计量
- F值越大,说明该特征与房价相关性越强
-
选择示例:
所有特征及其F分数:
| 特征 | F分数 | 排名 |
|---|---|---|
| area | 1250 | 1 |
| area_per_room | 980 | 2 |
| location_市中心 | 850 | 3 |
| age | 720 | 4 |
| style_现代 | 650 | 5 |
| … | … | … |
| style_欧式 | 45 | 12 |
选择Top 10后,丢弃最后2个弱相关特征
===== 第7步:特征重要性评估 =====
rf = RandomForestRegressor(n_estimators=100, random_state=42)
rf.fit(X_selected, y)
importance = rf.feature_importances_
feature_importance_df = pd.DataFrame({
'feature': selected_features,
'importance': importance
}).sort_values('importance', ascending=False)
print("\n特征重要性排序:")
print(feature_importance_df)
解释说明:
- 目的:用随机森林模型评估每个特征的"贡献度"
- 原理:随机森林在训练时会随机选择特征,如果一个特征经常被用于分割节点且能显著降低- 误差,说明这个特征很重要
- 输出示例:
特征重要性排序:
feature importance
0 area 0.3521 ← 面积最重要(占35.21%)
1 area_per_room 0.2134 ← 人均面积次重要
2 location_市中心 0.1567 ← 位置也很关键
3 age 0.1089
4 rooms 0.0675
5 style_现代 0.0456
...
- 业务解读:
- 面积决定了房子价值的基础(35%)
- 单价(人均面积)反映了性价比(21%)
- 地段是核心溢价因素(16%)
- 房龄、房间数、风格是辅助因素
完整流程
5、 本章节速记
特征工程分四步,洗转选评不马虎;
缺失异常先处理,交互时序造新图;
归一标准化转换,过滤包裹嵌入法;
业务知识是灵魂,模型上限靠它出。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)