文章目录
- 数据划分与特征工程
-
- 一、数据集划分
-
- [1.1 为什么要先划分再处理?](#1.1 为什么要先划分再处理?)
- [1.2 API - train_test_split](#1.2 API - train_test_split)
- 二、特征工程回忆
- [三、特征提取(Feature Extraction)](#三、特征提取(Feature Extraction))
-
- [3.1 字典特征提取:DictVectorizer](#3.1 字典特征提取:DictVectorizer)
- [3.2 文本特征提取:CountVectorizer](#3.2 文本特征提取:CountVectorizer)
- [3.3 文本特征提取:TfidfVectorizer](#3.3 文本特征提取:TfidfVectorizer)
- [四、特征预处理(Feature Preprocessing)](#四、特征预处理(Feature Preprocessing))
-
- [4.1 归一化(Min-Max Scaling)](#4.1 归一化(Min-Max Scaling))
- [4.2 标准化(Z-score Standardization)](#4.2 标准化(Z-score Standardization))
- [4.3 归一化 vs 标准化](#4.3 归一化 vs 标准化)
数据划分与特征工程
一、数据集划分
数据划分不属于特征工程,它是特征工程的前置操作。
1.1 为什么要先划分再处理?
防止数据泄漏(Data Leakage)。标准化、归一化等操作需要从数据中"学参数"(均值、标准差、最大最小值等),如果测试集也混进去一起算,测试集的信息就污染了训练过程,评估结果虚高,后面对真正的新数据就会暴露问题。
顺序原则:
- 不需要学参数的操作(去除 HTML 标签、全量去停用词)→ 可以在划分前对全量数据统一做。
- 需要学参数的操作 (算均值/标准差、最大/最小值、类别编码映射)→ 必须先划分,只用训练集
fit,然后transform测试集。
1.2 API - train_test_split
所属模块: sklearn.model_selection(助记:"模型选择"模块)
python
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(
X, y, # 特征矩阵、标签向量
test_size=0.2, # 测试集占比,常用 0.2 或 0.3
train_size=None, # 训练集占比,通常不填,由 test_size 推算
random_state=42, # 随机种子,固定后每次划分结果一致
shuffle=True, # 划分前是否打乱(默认 True)
stratify=y # 分层抽样:保持各类别比例不变
)
| 参数 | 类型 | 默认值 | 含义 |
|---|---|---|---|
test_size |
float/int | None |
测试集比例(0.0~1.0)或样本数 |
train_size |
float/int | None |
训练集比例或样本数,通常不填 |
random_state |
int | None |
随机种子,固定可复现结果 |
shuffle |
bool | True |
划分前是否打乱数据 |
stratify |
array-like | None |
按标签比例分层抽样,分类任务强烈建议设置 最终保证:训练集里 A:B = 测试集里 A:B = 原始数据集里 A:B |
返回值: 四个数组,按顺序为 X_train, X_test, y_train, y_test。
python
# 完整示例:按 8:2 分层划分
X = df.drop('label', axis=1)
y = df['label']
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42, stratify=y
)
二、特征工程回忆
回忆概述篇的笔记,特征工程包含:特征提取、特征预处理、特征降维、特征选择、特征组合。这里先展开最常用的前两类-特征提取和特征预处理。
| 类别 | 核心动作 | 本篇覆盖 | 后续详述 |
|---|---|---|---|
| 特征提取 | 原始数据 → 数值特征 | DictVectorizer、CountVectorizer、TfidfVectorizer |
Word2Vec、BERT嵌入、图像特征(SIFT/HOG/CNN) |
| 特征预处理 | 数值变换/缩放/编码 | MinMaxScaler、StandardScaler |
One-Hot、Label、Target 编码、RobustScaler |
| 特征降维 | 高维 → 低维 | --- | PCA、LDA、t-SNE |
| 特征选择 | 筛选有用特征、丢弃冗余 | --- | 过滤法、包裹法、嵌入法、L1正则化 |
| 特征组合 | 交叉/乘积构造交互特征 | --- | 多项式特征、交叉特征 |
三、特征提取(Feature Extraction)
3.1 字典特征提取:DictVectorizer
-
所属模块:
sklearn.feature_extraction -
什么时候用: 数据是字典列表的形式,比如
[{'city': '北京', 'gender': '男'}, ...]。 -
本质: 对类别字段做 One-Hot 编码,每个类别取值变成独立的一列 0/1。
python
from sklearn.feature_extraction import DictVectorizer
data = [
{'city': '北京', 'gender': '男'},
{'city': '上海', 'gender': '女'},
{'city': '北京', 'gender': '女'}
]
dv = DictVectorizer(sparse=True) # sparse=True:返回稀疏矩阵,节省内存
result = dv.fit_transform(data)
print("特征名:", dv.get_feature_names_out())
print("转换结果:\n", result)
输出:
text
特征名: ['city=上海' 'city=北京' 'gender=女' 'gender=男']
转换结果:
[[0. 1. 0. 1.] ← 第1条:city=北京(1), gender=男(1)
[1. 0. 1. 0.] ← 第2条:city=上海(1), gender=女(1)
[0. 1. 1. 0.]] ← 第3条:city=北京(1), gender=女(1)
可以看到:3 条原始字典 → 4 列 One-Hot 特征矩阵。city 有 {北京,上海} 两种取值 → 2 列;gender 有 {男,女} 两种取值 → 2 列。
| 参数 | 含义 |
|---|---|
sparse |
默认 True,返回稀疏矩阵;维度高且多数为 0 时大幅节省内存 |
核心方法:
| 方法 | 作用 |
|---|---|
fit(data) |
扫描数据,学习所有类别取值 |
transform(data) |
按已学特征名转为数值矩阵 |
fit_transform(data) |
一步完成 |
get_feature_names_out() |
获取转换后特征名列表 |
inverse_transform(X) |
数值矩阵还原为字典列表 |
3.2 文本特征提取:CountVectorizer
-
所属模块:
sklearn.feature_extraction.text -
核心思想(词袋模型): 把每篇文档变成一个词频向量,只统计每个词出现了多少次,不管词序。就像一个袋子把词装进去,不看先后顺序。
python
from sklearn.feature_extraction.text import CountVectorizer
cv = CountVectorizer(
max_features=1000, # 最多保留 1000 个高频词(控制维度)
stop_words='english', # 移除停用词(也可传自定义列表如 ['的','了'])
ngram_range=(1, 2), # 同时提取单个词和双词组合
min_df=1, # 至少在 1 篇文档中出现才保留
max_df=0.8 # 出现在超过 80% 文档中的高频词忽略
)
corpus = ['I love machine learning', 'Machine learning is great']
X = cv.fit_transform(corpus) # 返回稀疏矩阵
print("词表(按字母排序):", cv.get_feature_names_out())
print("词频矩阵(密集形式):\n", X.toarray())
输出:
text
词表(按字母排序): ['great' 'learning great' 'love' 'love machine']
词频矩阵(密集形式):
[[0 0 1 1]
[1 1 0 0]]
| 常用参数 | 含义 |
|---|---|
max_features |
按词频保留前 N 个词,控制维度的最常用方式 |
stop_words |
'english' 或自定义列表,移除无区分度的高频词 |
ngram_range |
(1,1) 仅单词,(1,2) 加双词组合,捕捉局部语序 |
min_df / max_df |
过滤太罕见/太常见的词 |
返回值: fit_transform() 返回稀疏矩阵(scipy.sparse.csr_matrix),形状 (文档数, 词表大小),可通过 .toarray() 转 NumPy 数组。
3.3 文本特征提取:TfidfVectorizer
-
所属模块:
sklearn.feature_extraction.text -
解决的问题:
CountVectorizer只看词频。TF-IDF 在词频基础上加入了"这个词在整个语料库中的区分能力"。也就是说TF-IDF的主要思想就是:如果某个词或短语在一篇文章中出现的概率高,并且在其他文章中很少出现,则认为此词或者短语具有很好的类别区分能力,适合用来做分类。 -
公式:TF * IDF
- TF(词频): 这个词在这篇文档中出现得多频繁?TF 高 = 本文档反复提到它。但不区分"主题词"和"通用词"。
TF ( t , d ) = 词 t 在文档 d 中的次数 文档 d 的总词数 \text{TF}(t, d) = \frac{\text{词 } t \text{ 在文档 } d \text{ 中的次数}}{\text{文档 } d \text{ 的总词数}} TF(t,d)=文档 d 的总词数词 t 在文档 d 中的次数 - IDF(逆文档频率): 这个词在整个语料库中有多少区分度?
IDF ( t ) = log ( 文档总数 包含词 t 的文档数 + 1 ) + 1 \text{IDF}(t) = \log\left(\frac{\text{文档总数}}{\text{包含词 } t \text{ 的文档数} + 1}\right) + 1 IDF(t)=log(包含词 t 的文档数+1文档总数)+1- 几乎所有文档都有(如"的")→ 分母大 → IDF 小
- 仅少数文档有(如"神经网络")→ 分母小 → IDF 大
- TF(词频): 这个词在这篇文档中出现得多频繁?TF 高 = 本文档反复提到它。但不区分"主题词"和"通用词"。
注意TF依据本文档,IDF依据语料库(文档集合)
python
from sklearn.feature_extraction.text import TfidfVectorizer
# 和 CountVectorizer 同样的语料,对比效果
tfidf = TfidfVectorizer(
max_features=1000, # 最多保留 1000 个高频词(控制维度)
stop_words='english', # 移除停用词(也可传自定义列表如 ['的','了'])
ngram_range=(1, 2), # 同时提取单个词和双词组合
min_df=1, # 至少在 1 篇文档中出现才保留
max_df=0.8 # 出现在超过 80% 文档中的高频词忽略
)
corpus = [
'I love machine learning', # 文档1
'Machine learning is great' # 文档2
]
X = tfidf.fit_transform(corpus)
print("词表:", tfidf.get_feature_names_out())
print("TF-IDF 矩阵:\n", X.toarray())
输出:
text
词表: ['great' 'learning great' 'love' 'love machine']
TF-IDF 矩阵:
[[0. 0. 0.70710678 0.70710678]
[0.70710678 0.70710678 0. 0. ]]
TfidfVectorizer 继承了 CountVectorizer 的全部参数,额外增加了:
| 独有参数 | 含义 |
|---|---|
use_idf |
默认 True。设 False 退化回纯 TF |
smooth_idf |
默认 True,平滑处理防止除零 |
norm |
'l2'(每行缩放为单位长度)、'l1' 或 None |
sublinear_tf |
True 时对 TF 取 1 + log(TF),抑制高频词 |
返回值: 稀疏矩阵,每个值不再是词频而是 TF-IDF 加权分数。
四、特征预处理(Feature Preprocessing)
对各特征做数值变换、缩放或编码,让不同量纲的特征"对齐",模型不被数值大小带偏。
4.1 归一化(Min-Max Scaling)
核心公式(缩放到 0, 1):
x ′ = x − x min x max − x min x' = \frac{x - x_{\text{min}}}{x_{\text{max}} - x_{\text{min}}} x′=xmax−xminx−xmin
推导分两步:
- 平移:
x - x_min,最小值移到 0,范围变为[0, x_max - x_min] - 缩放: 除以范围长度,最大值恰好变 1
通用形式(扩展到 a, b):
x ′ = a + ( x − x min ) ( b − a ) x max − x min x' = a + \frac{(x - x_{\text{min}})(b - a)}{x_{\text{max}} - x_{\text{min}}} x′=a+xmax−xmin(x−xmin)(b−a)
其实就是:先算出 x 在 0,1 里的比例位置 → 再映射到 a, b。a=0, b=1 就是第一个公式。需要非 0,1 区间时(如 tanh 激活函数适合 -1,1)用通用形式。
API: sklearn.preprocessing.MinMaxScaler
python
from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler(feature_range=(0, 1)) # 默认 [0,1]
# 核心:fit 只在训练集!
scaler.fit(X_train) # 学 x_min、x_max
X_train_scaled = scaler.transform(X_train) # 套用
X_test_scaled = scaler.transform(X_test) # 测试集只能用训练集学的参数!
# 训练集一步到位:scaler.fit_transform(X_train)
局限: 对异常值极度敏感,一个极端值会拉大范围,把正常数据压缩到极小空间。
4.2 标准化(Z-score Standardization)
核心公式:
x ′ = x − μ σ x' = \frac{x - \mu}{\sigma} x′=σx−μ
μ 是均值,σ 是标准差。分两步理解:
- 减均值: 解决的是特征之间的不一致问题,让所有特征的均值都围绕0,消除不同特征在中心位置上的巨大差异。
- 除标准差: 解决的是特征内部的尺度不统一问题,让每个特征自身的波动幅度都标准化为1,保证单个特征内部离散程度一致。
API: sklearn.preprocessing.StandardScaler
python
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler(with_mean=True, with_std=True) # 默认值
scaler.fit(X_train)
X_train_scaled = scaler.transform(X_train)
X_test_scaled = scaler.transform(X_test)
| 参数 | 含义 |
|---|---|
with_mean |
默认 True,减均值。稀疏矩阵需设 False |
with_std |
默认 True,除标准差 |
copy |
默认 True,复制后操作 |
fit/transform/fit_transform的区别sklearn 所有 Transformer 都遵循这个约定,极其重要。原因请见机器学习概述篇,同本篇第一个知识点。
方法 做了什么 用在哪个数据上 fit(X)学参数(均值、标准差、最大值、词表......) 只训练集 transform(X)套用已学的规则做转换 训练集、测试集、新数据 fit_transform(X)先 fit 再 transform,一步 只训练集
4.3 归一化 vs 标准化
| 归一化 | 标准化 | |
|---|---|---|
| 输出 | 固定区间 0,1 或 a,b | 均值为 0,标准差为 1 |
| 异常值 | 极度敏感 | 相对鲁棒 |
| 分布假设 | 无 | 正态时效果佳 |
| 稀疏保持 | ✅ | ❌(0 会变非零) |
| 典型场景 | KNN、K-Means、图像 | 线性回归、SVM、PCA、神经网络 |
选择原则: 有异常值 → StandardScaler 或 RobustScaler;需稀疏 → MinMaxScaler;不确定 → 先试 StandardScaler。
特征提取和特征预处理是特征工程中最先接触、最常用的两块。降维、选择、组合在后面学具体算法时按需补充。
以上为个人学习总结,旨在梳理个人理解。如有疏漏或不当之处,欢迎指正与交流。如果文章对你有帮助,别忘了点个赞、留个言~ 我们下篇再见!