Sklearn 特征工程
包含 sklearn.feature_extraction(特征提取)、sklearn.feature_selection(特征选择)和 sklearn.calibration(概率校准)。
📝 文本特征提取
1. CountVectorizer --- 词频向量化 ⭐
python
from sklearn.feature_extraction.text import CountVectorizer
vectorizer = CountVectorizer(
input='content', # 'content','filename','file'
encoding='utf-8',
decode_error='strict', # 'strict','ignore','replace'
strip_accents=None, # 'ascii','unicode',None
lowercase=True, # 全部转为小写
preprocessor=None, # 自定义预处理函数
tokenizer=None, # 自定义分词函数
stop_words=None, # 'english', list, None
token_pattern=r'(?u)\b\w\w+\b', # 正则表达式
ngram_range=(1, 1), # (min_n, max_n)
analyzer='word', # 'word','char','char_wb'
max_df=1.0, # 文档频率上限(过滤高频词)
min_df=1, # 文档频率下限(过滤低频词)
max_features=None, # 最大词汇量
vocabulary=None, # 预定义词汇表
binary=False, # True=出现/不出现(非计数)
dtype=np.int64
)
X = vectorizer.fit_transform(documents)
# 关键属性
print(vectorizer.vocabulary_) # 词→索引映射
print(vectorizer.get_feature_names_out()) # 特征名
print(vectorizer.stop_words_) # 被去除的停用词
print(vectorizer.fixed_vocabulary_) # 是否使用预定义词汇表
# 查看词频
term_freqs = X.sum(axis=0) # 每个词的总出现次数
2. TfidfVectorizer --- TF-IDF 向量化 ⭐
使用频率最高的文本向量化方法。
python
from sklearn.feature_extraction.text import TfidfVectorizer
vectorizer = TfidfVectorizer(
input='content',
encoding='utf-8',
lowercase=True,
stop_words='english',
ngram_range=(1, 2), # uni-grams + bi-grams
max_df=0.8, # 过滤出现在 80% 以上文档的词
min_df=2, # 过滤出现少于 2 次的词
max_features=5000,
norm='l2', # 归一化: 'l1','l2',None
use_idf=True, # 是否使用 IDF
smooth_idf=True, # 平滑 IDF(防止除以 0)
sublinear_tf=False, # 使用 1+log(tf)
binary=False,
vocabulary=None
)
X = vectorizer.fit_transform(documents)
# 关键属性
print(vectorizer.idf_) # IDF 向量
print(vectorizer.vocabulary_)
print(vectorizer.fixed_vocabulary_)
3. TfidfTransformer --- TF-IDF 变换器
将词频矩阵转换为 TF-IDF 矩阵。
python
from sklearn.feature_extraction.text import TfidfTransformer
transformer = TfidfTransformer(
norm='l2',
use_idf=True,
smooth_idf=True,
sublinear_tf=False
)
X_tfidf = transformer.fit_transform(X_counts)
print(transformer.idf_)
CountVectorizer + TfidfTransformer = TfidfVectorizer(上面更简洁)
4. HashingVectorizer --- 哈希向量化
使用特征哈希(Hashing Trick),无词汇表、内存高效。
python
from sklearn.feature_extraction.text import HashingVectorizer
vectorizer = HashingVectorizer(
n_features=2**20, # 哈希特征维度
input='content',
encoding='utf-8',
lowercase=True,
stop_words='english',
ngram_range=(1, 2),
analyzer='word',
norm='l2',
alternate_sign=True, # 使用符号哈希
binary=False,
dtype=np.float64
)
X = vectorizer.fit_transform(documents)
# 注意: 无 vocabulary_ 属性(不可逆)
🖼️ 图像特征提取
python
from sklearn.feature_extraction.image import (
extract_patches_2d, # 提取 2D 图像块
reconstruct_from_patches_2d, # 从块重建图像
PatchExtractor, # 块提取器
grid_to_graph, # 像素网格图
img_to_graph, # 图像到图
)
from sklearn.feature_extraction.image import extract_patches_2d
import numpy as np
image = np.arange(16).reshape(4, 4)
# 提取所有 (2, 2) 的图像块
patches = extract_patches_2d(
image,
patch_size=(2, 2),
max_patches=None, # None=所有, int=随机采样
random_state=42
)
# patches.shape: (9, 2, 2) 对于 4x4 图像
# 从块重建图像
reconstructed = reconstruct_from_patches_2d(patches, image_size=(4, 4))
🗜️ 特征选择
1. 过滤法(Filter Methods)
VarianceThreshold --- 方差阈值
python
from sklearn.feature_selection import VarianceThreshold
selector = VarianceThreshold(threshold=0.0) # 移除方差为 0 的特征
X_selected = selector.fit_transform(X)
print(selector.variances_) # 每个特征的方差
print(selector.get_support()) # 布尔掩码
SelectKBest --- 选最佳 K 个特征 ⭐
python
from sklearn.feature_selection import SelectKBest, f_classif, chi2, mutual_info_classif
# 分类: f_classif(F 检验), chi2(卡方), mutual_info_classif(互信息)
selector = SelectKBest(
score_func=f_classif, # 评分函数
k=10 # 保留的特征数
)
X_selected = selector.fit_transform(X, y)
print(selector.scores_) # 每个特征的得分
print(selector.pvalues_) # 每个特征的 p 值(部分函数)
print(selector.get_support()) # 被选中的特征
# 回归对应的评分函数
from sklearn.feature_selection import f_regression, mutual_info_regression
selector_reg = SelectKBest(score_func=f_regression, k=10)
常用评分函数:
| 分类 | 回归 | 说明 |
|---|---|---|
f_classif |
f_regression |
F 检验 |
chi2 |
--- | 卡方检验(仅非负值) |
mutual_info_classif |
mutual_info_regression |
互信息(捕获非线性) |
| --- | r_regression |
Pearson 相关系数 |
SelectPercentile --- 按百分比选择
python
from sklearn.feature_selection import SelectPercentile
selector = SelectPercentile(
score_func=f_classif,
percentile=50 # 保留前 50% 的特征
)
X_selected = selector.fit_transform(X, y)
SelectFpr / SelectFdr / SelectFwe --- 基于假设检验
python
from sklearn.feature_selection import SelectFpr, SelectFdr, SelectFwe
# 控制假阳性率
selector = SelectFpr(score_func=f_classif, alpha=0.05)
# 控制错误发现率
selector = SelectFdr(score_func=f_classif, alpha=0.05)
# 按家族错误率选择
selector = SelectFwe(score_func=f_classif, alpha=0.05)
2. 包装法(Wrapper Methods)
RFE --- 递归特征消除 ⭐
python
from sklearn.feature_selection import RFE
from sklearn.linear_model import LogisticRegression
estimator = LogisticRegression(max_iter=1000)
selector = RFE(
estimator=estimator,
n_features_to_select=10, # 或 float (0~1) 表示比例
step=1, # 每次移除的特征数
verbose=0,
importance_getter='auto' # 'auto','coef_','feature_importances_'
)
selector.fit(X, y)
print(selector.support_) # 被选中特征的掩码
print(selector.ranking_) # 特征的排名(1=最优)
print(selector.n_features_) # 选中特征数
print(selector.estimator_) # 训练好的最终估计器
# 变换
X_selected = selector.transform(X)
RFECV --- 带交叉验证的 RFE ⭐
python
from sklearn.feature_selection import RFECV
from sklearn.svm import SVC
estimator = SVC(kernel='linear')
selector = RFECV(
estimator=estimator,
step=1,
min_features_to_select=1,
cv=5, # 或 StratifiedKFold 等
scoring='accuracy',
verbose=0,
n_jobs=-1,
importance_getter='auto'
)
selector.fit(X, y)
print(selector.support_)
print(selector.ranking_)
print(selector.n_features_) # 最优特征数
print(selector.cv_results_) # 各特征数的交叉验证结果
print(selector.grid_scores_) # 已弃用,使用 cv_results_
# 可视化
import matplotlib.pyplot as plt
n_features = range(selector.min_features_to_select,
len(selector.cv_results_['mean_test_score']) + 1)
plt.figure(figsize=(10, 6))
plt.errorbar(n_features,
selector.cv_results_['mean_test_score'],
yerr=selector.cv_results_['std_test_score'])
plt.xlabel('Number of features')
plt.ylabel('Cross-validation score')
plt.title('RFECV: Optimal Number of Features')
plt.axvline(selector.n_features_, color='r', linestyle='--',
label=f'Optimal: {selector.n_features_}')
plt.legend()
plt.show()
SequentialFeatureSelector --- 顺序特征选择
python
from sklearn.feature_selection import SequentialFeatureSelector
selector = SequentialFeatureSelector(
estimator=LogisticRegression(max_iter=1000),
n_features_to_select=10, # 或 'auto'(用 tol 判断)
tol=None, # 分数改善低于 tol 则停止
direction='forward', # 'forward'(前向) 或 'backward'(后向)
scoring='accuracy',
cv=5,
n_jobs=-1
)
selector.fit(X, y)
print(selector.support_)
print(selector.get_support())
X_selected = selector.transform(X)
3. 嵌入法(Embedded Methods)
SelectFromModel ⭐
使用任何有 coef_ 或 feature_importances_ 属性的估计器选择特征。
python
from sklearn.feature_selection import SelectFromModel
from sklearn.linear_model import LassoCV
from sklearn.ensemble import RandomForestClassifier
# 方式一: L1 正则化(Lasso)
lasso = LassoCV(cv=5, random_state=42).fit(X, y)
selector = SelectFromModel(
estimator=lasso,
threshold='median', # 或 'mean', '1.25*mean', float
prefit=True, # True=已拟合, False=先 fit
norm_order=1, # 系数范数
max_features=None # 最大特征数
)
X_selected = selector.transform(X)
# 方式二: 树模型特征重要性
rf = RandomForestClassifier(n_estimators=100, random_state=42)
selector = SelectFromModel(
estimator=rf,
threshold='0.5*mean', # 阈值为平均重要性的 0.5 倍
prefit=False
)
X_selected = selector.fit_transform(X, y)
# 属性
print(selector.estimator_) # 训练好的估计器
print(selector.threshold_) # 使用的阈值
print(selector.get_support()) # 选中的特征
print(selector.max_features_) # 最大特征数
📊 特征字典提取
DictVectorizer
将字典列表转换为特征矩阵(自动 One-Hot 编码类别值)。
python
from sklearn.feature_extraction import DictVectorizer
data = [
{'city': 'Beijing', 'temp': 25},
{'city': 'Shanghai', 'temp': 28, 'humidity': 70},
{'city': 'Beijing', 'temp': 22, 'humidity': 55}
]
vec = DictVectorizer(
dtype=np.float64,
separator='=',
sparse=True
)
X = vec.fit_transform(data)
# temp city=Beijing city=Shanghai humidity
# 0 25.0 1.0 0.0 0.0
# 1 28.0 0.0 1.0 70.0
# 2 22.0 1.0 0.0 55.0
print(vec.feature_names_)
print(vec.vocabulary_)
# 逆变换
data_reconstructed = vec.inverse_transform(X)
📝 特征特征(Feature Characterizer)
FeatureHasher --- 特征哈希
python
from sklearn.feature_extraction import FeatureHasher
hasher = FeatureHasher(
n_features=2**10, # 输出特征维度
input_type='dict', # 'dict','pair','string'
dtype=np.float64,
alternate_sign=True
)
X = hasher.fit_transform(feature_dicts)
# 无 vocabulary_ --- 不可逆
🎯 概率校准
CalibratedClassifierCV --- 概率校准 ⭐
让模型的概率估计更准确。
python
from sklearn.calibration import CalibratedClassifierCV
from sklearn.svm import SVC
# 方法一: 包裹任意分类器
base_model = SVC(probability=False) # 不一定要开启概率
calibrated = CalibratedClassifierCV(
estimator=base_model,
method='sigmoid', # 'sigmoid'(Platt Scaling) 或 'isotonic'
cv=5, # 'prefit' 或 int 或 cross-validator
n_jobs=None,
ensemble=True # True=每个 fold 一个模型集成,False=单模型
)
calibrated.fit(X_train, y_train)
y_prob = calibrated.predict_proba(X_test)
y_pred = calibrated.predict(X_test)
# 关键属性
print(calibrated.calibrated_classifiers_) # 校准后的分类器列表
print(calibrated.classes_)
Platt Scaling vs Isotonic Regression:
| method | 适用场景 | 数据量 |
|---|---|---|
'sigmoid' |
默认,更稳定 | 较少数据也可 |
'isotonic' |
更灵活(非参数) | 需要更多数据(>1000) |
calibration_curve() --- 校准曲线
python
from sklearn.calibration import calibration_curve
import matplotlib.pyplot as plt
prob_true, prob_pred = calibration_curve(
y_true, y_prob,
n_bins=10,
strategy='uniform' # 'uniform' 或 'quantile'
)
# 绘制
plt.plot([0, 1], [0, 1], 'k--', label='Perfectly calibrated')
plt.plot(prob_pred, prob_true, 's-', label='Model')
plt.xlabel('Mean predicted probability')
plt.ylabel('Fraction of positives')
plt.legend()
plt.show()
📝 完整特征工程 Pipeline 模板
python
from sklearn.pipeline import Pipeline
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.impute import SimpleImputer
from sklearn.feature_selection import SelectFromModel
from sklearn.ensemble import RandomForestClassifier
# 1. 预处理
preprocessor = ColumnTransformer([
('num', StandardScaler(), numerical_cols),
('cat', OneHotEncoder(handle_unknown='ignore'), categorical_cols),
])
# 2. 特征选择
feature_selector = SelectFromModel(
RandomForestClassifier(n_estimators=100, random_state=42),
threshold='median'
)
# 3. 最终模型
final_model = RandomForestClassifier(n_estimators=200, random_state=42)
# 完整管道
pipeline = Pipeline([
('preprocessor', preprocessor),
('feature_selection', feature_selector),
('classifier', final_model)
])
pipeline.fit(X_train, y_train)
print(f"Test accuracy: {pipeline.score(X_test, y_test):.3f}")
print(f"Selected features: {pipeline.named_steps['feature_selection'].get_support().sum()}")
\[sklearn-总览\|← 返回总览\]