scikit-learn 完全指南
scikit-learn 是 Python 最成熟的机器学习库,提供监督学习、无监督学习、模型选择与评估的完整工具链,所有算法遵循统一的 fit/predict/transform 接口。 与其他框架的对比: 适合场景:结构化(表格)数据的分类、回归、聚类;需要快速建立 baseline;特征工程 Pipeline 构建;模型选择与超参调优。 不适合场景:图像/音频/文本深度学习(用 PyTorch完全指南(/pytorchwan-quan-zhi-nan/) 或 HuggingFace Transformers完全指南(/huggingface-tra
官方文档:https://scikit-learn.org/stable/
适用版本:scikit-learn 1.8.0(2026-05-07 核实)
概述
scikit-learn 是 Python 最成熟的机器学习库,提供监督学习、无监督学习、模型选择与评估的完整工具链,所有算法遵循统一的 fit/predict/transform 接口。
与其他框架的对比:
| scikit-learn | PyTorch | XGBoost | |
|---|---|---|---|
| 定位 | 经典 ML 算法大全 | 深度学习框架 | 梯度提升专用 |
| 上手成本 | 低(统一接口) | 高(需手写训练循环) | 中 |
| 适合数据量 | 中小型(内存能加载) | 无上限(批量训练) | 中大型 |
| GPU 支持 | 有限(部分算法) | 原生 | 支持 |
| 可解释性 | 高(线性模型、决策树) | 低(黑盒) | 中 |
适合场景:结构化(表格)数据的分类、回归、聚类;需要快速建立 baseline;特征工程 Pipeline 构建;模型选择与超参调优。
不适合场景:图像/音频/文本深度学习(用 PyTorch完全指南 或 HuggingFace Transformers完全指南);超大规模分布式训练。
安装
pip install scikit-learn
核心设计:Estimator 接口
所有 scikit-learn 对象实现统一接口:
| 方法 | 适用对象 | 说明 |
|---|---|---|
fit(X, y) |
Estimator(含 Transformer) | 用训练数据拟合模型;无监督只需 X |
predict(X) |
Classifier / Regressor | 返回预测标签或数值 |
predict_proba(X) |
支持概率输出的 Classifier | 返回每类的概率,形状 (n, n_classes) |
transform(X) |
Transformer | 对数据做变换(如归一化、降维) |
fit_transform(X) |
Transformer | 等价于 fit(X).transform(X),避免两次调用 |
score(X, y) |
Estimator | 返回默认评估指标(分类器返回 accuracy,回归返回 R²) |
set_params(**params) |
所有 Estimator | 修改超参数,用于 GridSearch |
get_params() |
所有 Estimator | 获取当前超参数字典 |
数据预处理(sklearn.preprocessing)
StandardScaler
零均值、单位方差标准化(Z-score)。
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler(copy=True, with_mean=True, with_std=True)
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
copy |
bool |
True |
是否拷贝数据;False 原地修改节省内存,但会修改原数组 |
with_mean |
bool |
True |
是否减去均值(中心化);稀疏矩阵设 False 否则报错 |
with_std |
bool |
True |
是否除以标准差;False 只中心化不缩放 |
from sklearn.preprocessing import StandardScaler
X_train = [[0, 0], [0, 0], [1, 1], [1, 1]]
scaler = StandardScaler()
scaler.fit(X_train)
# 务必只在训练集上 fit,测试集只做 transform
X_test = scaler.transform([[2, 2], [-1, -1]])
print(scaler.mean_) # [0.5 0.5]
print(scaler.scale_) # [0.5 0.5]
MinMaxScaler
将特征缩放到指定范围 [feature_range[0], feature_range[1]]。
from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler(feature_range=(0, 1), copy=True, clip=False)
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
feature_range |
tuple[float, float] |
(0, 1) |
目标范围;两端点必须满足 min < max |
copy |
bool |
True |
是否拷贝数据 |
clip |
bool |
False |
True 时超出训练范围的测试值被裁剪到 feature_range 内 |
OneHotEncoder
将类别特征编码为 one-hot 矩阵。
from sklearn.preprocessing import OneHotEncoder
enc = OneHotEncoder(
categories='auto',
drop=None,
sparse_output=True,
dtype=float,
handle_unknown='error',
min_frequency=None,
max_categories=None,
)
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
categories |
"auto" 或 list[list] |
"auto" |
"auto" 从数据中推断;或手动指定每列的类别列表 |
drop |
None | "first" | "if_binary" |
None |
删除冗余列;"first" 删第一列(避免多重共线性);"if_binary" 仅对二值特征删除 |
sparse_output |
bool |
True |
True 返回稀疏矩阵(节省内存);False 返回 ndarray |
dtype |
numeric type |
float |
输出数组的数值类型 |
handle_unknown |
"error" | "ignore" | "infrequent_if_exist" |
"error" |
遇到训练时未见过的类别的处理方式;"ignore" 输出全零列 |
min_frequency |
int | float | None |
None |
低于此频率的类别归入 infrequent 类 |
max_categories |
int | None |
None |
每列最多保留的类别数,超出部分合并为 infrequent |
from sklearn.preprocessing import OneHotEncoder
import numpy as np
enc = OneHotEncoder(sparse_output=False, handle_unknown='ignore')
X = [['cat'], ['dog'], ['fish']]
enc.fit(X)
# 测试集有未见类别 'bird',handle_unknown='ignore' 输出全零
print(enc.transform([['dog'], ['bird']]))
# [[0. 1. 0.]
# [0. 0. 0.]]
LabelEncoder
对目标变量(y)的类别进行整数编码。
from sklearn.preprocessing import LabelEncoder
le = LabelEncoder()
le.fit(['cat', 'dog', 'fish'])
print(le.transform(['dog', 'cat'])) # [1 0]
print(le.inverse_transform([2])) # ['fish']
LabelEncoder 无超参数,不应用于输入特征(用 OrdinalEncoder 代替)。
PolynomialFeatures
生成多项式特征,用于线性模型捕捉非线性关系。
from sklearn.preprocessing import PolynomialFeatures
poly = PolynomialFeatures(degree=2, interaction_only=False, include_bias=True, order='C')
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
degree |
int | tuple[int,int] |
2 |
多项式最高次数;tuple 指定范围 (min_degree, max_degree) |
interaction_only |
bool |
False |
True 只生成交叉项(不含 x² 类纯次方项) |
include_bias |
bool |
True |
是否包含偏置列(全为 1 的列) |
order |
"C" | "F" |
"C" |
输出数组的内存布局;"C" 行优先,"F" 列优先 |
线性模型(sklearn.linear_model)
LogisticRegression
逻辑回归分类器,适合线性可分的二分类和多分类问题。
from sklearn.linear_model import LogisticRegression
clf = LogisticRegression(
penalty='l2',
dual=False,
tol=1e-4,
C=1.0,
fit_intercept=True,
intercept_scaling=1,
class_weight=None,
random_state=None,
solver='lbfgs',
max_iter=100,
multi_class='deprecated',
verbose=0,
warm_start=False,
n_jobs=None,
l1_ratio=None,
)
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
penalty |
"l1" | "l2" | "elasticnet" | None |
"l2" |
正则化类型;None 无正则;l1 需 solver='liblinear' 或 'saga' |
C |
float |
1.0 |
正则化强度的倒数;越小正则越强;必须 > 0 |
solver |
str |
"lbfgs" |
优化算法:lbfgs(小数据集)、liblinear(小/稀疏)、saga(大数据集/L1)、newton-cg、newton-cholesky、sag |
max_iter |
int |
100 |
求解器最大迭代次数;若不收敛会抛出 ConvergenceWarning |
class_weight |
dict | "balanced" | None |
None |
类别权重;"balanced" 自动按类频率倒数加权(处理不平衡数据) |
random_state |
int | None |
None |
随机种子(solver='sag'/'saga'/'liblinear' 时使用) |
n_jobs |
int | None |
None |
多分类时并行数;-1 使用全部 CPU |
l1_ratio |
float | None |
None |
ElasticNet 混合比例;0=纯L2,1=纯L1;仅 penalty='elasticnet' 时有效 |
warm_start |
bool |
False |
True 用上次 fit 的结果初始化,用于增量训练 |
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
X, y = load_iris(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
clf = LogisticRegression(max_iter=1000, C=0.1)
clf.fit(X_train, y_train)
print(clf.score(X_test, y_test)) # accuracy
print(clf.predict_proba(X_test[:2])) # 概率矩阵
LinearRegression
最小二乘线性回归。
from sklearn.linear_model import LinearRegression
reg = LinearRegression(fit_intercept=True, copy_X=True, n_jobs=None, positive=False)
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
fit_intercept |
bool |
True |
是否拟合截距;False 假设数据已中心化 |
copy_X |
bool |
True |
False 原地修改 X(节省内存,但会修改原始数据) |
n_jobs |
int | None |
None |
计算并行数;仅多目标回归时有效 |
positive |
bool |
False |
True 强制系数非负(非负约束最小二乘) |
Ridge
L2 正则化线性回归(岭回归)。
from sklearn.linear_model import Ridge
reg = Ridge(alpha=1.0, fit_intercept=True, copy_X=True, max_iter=None,
tol=1e-4, solver='auto', positive=False, random_state=None)
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
alpha |
float | array-like |
1.0 |
正则化系数;越大正则越强;为 0 等价于 LinearRegression;array 时对每个目标单独设置 |
solver |
str |
"auto" |
求解器:auto(自动选择)、svd、cholesky、lsqr、sparse_cg、sag、saga、lbfgs |
max_iter |
int | None |
None |
迭代求解器最大迭代次数 |
Lasso
L1 正则化线性回归(Lasso),产生稀疏解(特征选择)。
from sklearn.linear_model import Lasso
reg = Lasso(alpha=1.0, fit_intercept=True, precompute=False, copy_X=True,
max_iter=1000, tol=1e-4, warm_start=False, positive=False,
random_state=None, selection='cyclic')
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
alpha |
float |
1.0 |
L1 正则化系数;越大稀疏度越高(更多系数为零) |
max_iter |
int |
1000 |
坐标下降最大迭代次数 |
selection |
"cyclic" | "random" |
"cyclic" |
坐标更新策略;"random" 有时收敛更快 |
集成方法(sklearn.ensemble)
RandomForestClassifier
随机森林:并行训练多棵决策树,以投票方式聚合结果。
from sklearn.ensemble import RandomForestClassifier
clf = RandomForestClassifier(
n_estimators=100,
criterion='gini',
max_depth=None,
min_samples_split=2,
min_samples_leaf=1,
min_weight_fraction_leaf=0.0,
max_features='sqrt',
max_leaf_nodes=None,
min_impurity_decrease=0.0,
bootstrap=True,
oob_score=False,
n_jobs=None,
random_state=None,
verbose=0,
warm_start=False,
class_weight=None,
ccp_alpha=0.0,
max_samples=None,
monotonic_cst=None,
)
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
n_estimators |
int |
100 |
决策树数量;越多越稳定,但计算越慢 |
criterion |
"gini" | "entropy" | "log_loss" |
"gini" |
节点分裂的衡量标准 |
max_depth |
int | None |
None |
树最大深度;None 展开到所有叶子纯净为止(可能过拟合) |
min_samples_split |
int | float |
2 |
内部节点最少样本数才允许分裂;float 表示比例 |
min_samples_leaf |
int | float |
1 |
叶子节点最少样本数;增大可减少过拟合 |
max_features |
"sqrt" | "log2" | int | float | None |
"sqrt" |
每次分裂考虑的最大特征数;"sqrt" 适合分类,"auto" 已废弃 |
bootstrap |
bool |
True |
True 使用有放回抽样;False 使用全部训练数据 |
oob_score |
bool |
False |
True 使用袋外样本估计泛化误差(bootstrap=True 时可用) |
n_jobs |
int | None |
None |
并行树的训练数;-1 使用全部 CPU |
class_weight |
dict | "balanced" | "balanced_subsample" | None |
None |
类别权重 |
ccp_alpha |
float |
0.0 |
代价复杂度剪枝参数;0 不剪枝 |
max_samples |
int | float | None |
None |
bootstrap 时每棵树抽取的样本数;None 等于训练集大小 |
GradientBoostingClassifier
梯度提升:顺序训练,每棵树拟合前一棵的残差。准确率通常高于随机森林,但训练慢。
from sklearn.ensemble import GradientBoostingClassifier
clf = GradientBoostingClassifier(
loss='log_loss',
learning_rate=0.1,
n_estimators=100,
subsample=1.0,
criterion='friedman_mse',
min_samples_split=2,
min_samples_leaf=1,
min_weight_fraction_leaf=0.0,
max_depth=3,
min_impurity_decrease=0.0,
init=None,
random_state=None,
max_features=None,
verbose=0,
max_leaf_nodes=None,
warm_start=False,
validation_fraction=0.1,
n_iter_no_change=None,
tol=1e-4,
ccp_alpha=0.0,
)
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
learning_rate |
float |
0.1 |
每棵树的贡献缩减系数(步长);越小需要越多树 |
n_estimators |
int |
100 |
树的数量;与 learning_rate 反向调整(小步长 + 多树) |
subsample |
float |
1.0 |
每棵树训练时的样本比例;< 1 实现随机梯度提升,减少过拟合 |
max_depth |
int |
3 |
每棵树的最大深度;梯度提升通常用浅树(3–5) |
n_iter_no_change |
int | None |
None |
早停:连续 N 轮验证集分数无改善则停止 |
validation_fraction |
float |
0.1 |
早停时从训练集划分的验证比例 |
支持向量机(sklearn.svm)
SVC
支持向量机分类,适合高维、小数据集的分类问题。
from sklearn.svm import SVC
clf = SVC(
C=1.0,
kernel='rbf',
degree=3,
gamma='scale',
coef0=0.0,
shrinking=True,
probability=False,
tol=1e-3,
cache_size=200,
class_weight=None,
verbose=False,
max_iter=-1,
decision_function_shape='ovr',
break_ties=False,
random_state=None,
)
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
C |
float |
1.0 |
正则化参数;越小间隔越宽(欠拟合),越大越严格分类(过拟合) |
kernel |
"linear" | "poly" | "rbf" | "sigmoid" | "precomputed" |
"rbf" |
核函数类型;"rbf" 适合大多数场景;"linear" 适合线性可分 |
degree |
int |
3 |
多项式核的次数;仅 kernel='poly' 时有效 |
gamma |
"scale" | "auto" | float |
"scale" |
核系数;"scale" 使用 1/(n_features * X.var());"auto" 使用 1/n_features |
probability |
bool |
False |
True 启用概率估计(启用后会有额外开销,影响训练速度) |
cache_size |
float |
200 |
核矩阵缓存大小(MB);大数据集增大可加速 |
decision_function_shape |
"ovr" | "ovo" |
"ovr" |
多分类策略:"ovr" 一对多,"ovo" 一对一 |
聚类(sklearn.cluster)
KMeans
K-均值聚类,将数据分为 K 个簇。
from sklearn.cluster import KMeans
km = KMeans(
n_clusters=8,
init='k-means++',
n_init='auto',
max_iter=300,
tol=1e-4,
verbose=0,
random_state=None,
copy_x=True,
algorithm='lloyd',
)
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
n_clusters |
int |
8 |
簇的数量 K;需通过肘部法或轮廓系数确定 |
init |
"k-means++" | "random" | callable |
"k-means++" |
初始化方法;"k-means++" 加速收敛并提升稳定性 |
n_init |
int | "auto" |
"auto" |
不同初始化的运行次数,取最优;"auto" 对 k-means++ 使用 10,random 使用 1 |
max_iter |
int |
300 |
单次运行最大迭代次数 |
algorithm |
"lloyd" | "elkan" |
"lloyd" |
算法实现;"elkan" 用三角不等式加速,但内存更多 |
from sklearn.cluster import KMeans
import numpy as np
X = np.array([[1, 2], [1, 4], [1, 0], [10, 2], [10, 4], [10, 0]])
km = KMeans(n_clusters=2, random_state=42, n_init=10)
km.fit(X)
print(km.labels_) # 每个样本的簇标签
print(km.cluster_centers_) # 簇中心坐标
print(km.inertia_) # 误差平方和(越小越好)
DBSCAN
基于密度的聚类,不需要预先指定 K,能发现任意形状的簇并识别噪声点。
from sklearn.cluster import DBSCAN
db = DBSCAN(
eps=0.5,
min_samples=5,
metric='euclidean',
metric_params=None,
algorithm='auto',
leaf_size=30,
p=None,
n_jobs=None,
)
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
eps |
float |
0.5 |
两个样本被视为邻居的最大距离;核心超参数,需根据数据尺度调整 |
min_samples |
int |
5 |
核心点的最少邻居数(含自身);增大可减少噪声标签 |
metric |
str | callable |
"euclidean" |
距离度量;支持所有 scipy.spatial.distance 中的距离 |
algorithm |
"auto" | "ball_tree" | "kd_tree" | "brute" |
"auto" |
查找最近邻的算法 |
DBSCAN 的标签中 -1 表示噪声点(不属于任何簇)。
模型选择(sklearn.model_selection)
train_test_split
将数组或矩阵按比例随机分为训练集和测试集。
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(
*arrays,
test_size=None,
train_size=None,
random_state=None,
shuffle=True,
stratify=None,
)
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
*arrays |
indexable | 必填 | 要分割的数组(X, y, weights 等),所有数组必须等长 |
test_size |
float | int | None |
None |
float 表示比例(0–1),int 表示绝对数量;None 时默认 0.25 |
train_size |
float | int | None |
None |
同上;None 时取 1 - test_size |
random_state |
int | None |
None |
随机种子;固定种子保证结果可复现 |
shuffle |
bool |
True |
分割前是否打乱;时序数据应设 False |
stratify |
array-like | None |
None |
按此数组的类分布进行分层抽样;保证训练/测试集类别比例相同 |
cross_val_score
K 折交叉验证,返回每折的评分数组。
from sklearn.model_selection import cross_val_score
scores = cross_val_score(
estimator,
X,
y=None,
groups=None,
scoring=None,
cv=5,
n_jobs=None,
verbose=0,
fit_params=None,
params=None,
pre_dispatch='2*n_jobs',
error_score=nan,
)
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
estimator |
estimator | 必填 | 实现了 fit 的 sklearn 兼容对象 |
X |
array-like | 必填 | 特征矩阵 |
y |
array-like | None | None |
目标变量;无监督学习传 None |
scoring |
str | callable | None |
None |
评估指标;None 使用 estimator 的默认分数;字符串如 "f1_macro"、"roc_auc" |
cv |
int | CV splitter |
5 |
折数;或自定义 KFold/StratifiedKFold 对象 |
n_jobs |
int | None |
None |
并行折数;-1 使用全部 CPU |
from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import load_iris
X, y = load_iris(return_X_y=True)
clf = LogisticRegression(max_iter=1000)
scores = cross_val_score(clf, X, y, cv=5, scoring='accuracy')
print(f"Accuracy: {scores.mean():.3f} ± {scores.std():.3f}")
GridSearchCV
穷举超参数网格,用交叉验证选最优参数组合。
from sklearn.model_selection import GridSearchCV
search = GridSearchCV(
estimator,
param_grid,
scoring=None,
n_jobs=None,
refit=True,
cv=5,
verbose=0,
pre_dispatch='2*n_jobs',
error_score=nan,
return_train_score=False,
)
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
estimator |
estimator | 必填 | 待搜索的模型,需实现 fit/score |
param_grid |
dict | list[dict] |
必填 | 参数名(含 __ 分隔的 Pipeline 参数)到候选值列表的映射 |
scoring |
str | callable | list | dict | None |
None |
评估指标;多指标时用 dict 并需指定 refit |
cv |
int | CV splitter |
5 |
交叉验证折数 |
refit |
bool | str |
True |
找到最优参数后用全量数据重新训练;多指标时需指定用哪个指标 |
n_jobs |
int | None |
None |
并行候选数;-1 全部 CPU |
return_train_score |
bool |
False |
True 在 cv_results_ 中包含训练集分数(诊断过拟合用) |
from sklearn.model_selection import GridSearchCV
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_iris
X, y = load_iris(return_X_y=True)
param_grid = {
'n_estimators': [50, 100, 200],
'max_depth': [None, 3, 5],
}
search = GridSearchCV(
RandomForestClassifier(random_state=42),
param_grid,
cv=5,
scoring='accuracy',
n_jobs=-1,
)
search.fit(X, y)
print(search.best_params_) # {'max_depth': None, 'n_estimators': 100}
print(search.best_score_) # 0.973...
# search.best_estimator_ 是已用全量数据重训的最优模型
RandomizedSearchCV
随机采样超参数空间,比 GridSearchCV 更高效(适合大参数空间)。
from sklearn.model_selection import RandomizedSearchCV
search = RandomizedSearchCV(
estimator,
param_distributions,
n_iter=10,
scoring=None,
n_jobs=None,
refit=True,
cv=5,
verbose=0,
pre_dispatch='2*n_jobs',
random_state=None,
error_score=nan,
return_train_score=False,
)
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
param_distributions |
dict | list[dict] |
必填 | 参数到候选值列表或 scipy 分布对象的映射;连续超参用分布更高效 |
n_iter |
int |
10 |
随机采样次数;越大越接近 Grid Search 但耗时越多 |
random_state |
int | None |
None |
随机种子 |
Pipeline(sklearn.pipeline)
Pipeline
将多个预处理步骤和最终估计器串联,避免数据泄漏(fit_transform 仅在训练集执行)。
from sklearn.pipeline import Pipeline
pipe = Pipeline(steps, memory=None, verbose=False)
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
steps |
list[tuple[str, estimator]] |
必填 | 每个元素为 (name, transformer) 或 (name, estimator);最后一步可以是 Estimator |
memory |
None | str | Memory |
None |
缓存已拟合的 Transformer(加速 GridSearch 时相同参数不重新拟合) |
verbose |
bool |
False |
True 打印每步执行时间 |
访问步骤:pipe['scaler'] 或 pipe.named_steps['scaler']。
超参数路径:pipe.set_params(classifier__C=0.1)(stepname__param 格式)。
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import GridSearchCV
from sklearn.datasets import load_breast_cancer
X, y = load_breast_cancer(return_X_y=True)
# Pipeline 防止数据泄漏:Scaler 只在训练折 fit
pipe = Pipeline([
('scaler', StandardScaler()),
('clf', LogisticRegression(max_iter=1000)),
])
# 通过 __ 分隔符访问 Pipeline 内的超参数
param_grid = {
'clf__C': [0.01, 0.1, 1, 10],
'clf__penalty': ['l2'],
}
grid = GridSearchCV(pipe, param_grid, cv=5, n_jobs=-1)
grid.fit(X, y)
print(grid.best_params_)
评估指标(sklearn.metrics)
分类指标
from sklearn.metrics import (
accuracy_score, precision_score, recall_score, f1_score,
confusion_matrix, classification_report, roc_auc_score
)
# 二分类
y_true = [0, 1, 1, 0, 1]
y_pred = [0, 1, 0, 0, 1]
print(accuracy_score(y_true, y_pred)) # 0.8
print(precision_score(y_true, y_pred)) # 1.0
print(recall_score(y_true, y_pred)) # 0.667
print(f1_score(y_true, y_pred)) # 0.8
print(confusion_matrix(y_true, y_pred))
# [[2 0]
# [1 2]]
print(classification_report(y_true, y_pred)) # 多指标汇总
average 参数说明(多分类时必须指定):
| 值 | 说明 |
|---|---|
"binary" |
二分类,默认 positive label=1 |
"micro" |
全局统计 TP/FP/FN,适合样本不平衡 |
"macro" |
各类均值(等权),适合类别均衡 |
"weighted" |
按类别样本数加权均值,适合不平衡 |
回归指标
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
y_true = [3, -0.5, 2, 7]
y_pred = [2.5, 0.0, 2, 8]
print(mean_squared_error(y_true, y_pred)) # MSE = 0.375
print(mean_absolute_error(y_true, y_pred)) # MAE = 0.5
print(r2_score(y_true, y_pred)) # R² = 0.948
完整示例:端到端 ML 工作流
import numpy as np
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import classification_report, roc_auc_score
# 加载数据
X, y = load_breast_cancer(return_X_y=True)
print(f"Samples: {X.shape[0]}, Features: {X.shape[1]}, Classes: {np.unique(y)}")
# 分层划分训练/测试集(保证类别比例相同)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42, stratify=y
)
# 构建 Pipeline(Scaler 只在训练折 fit,防止数据泄漏)
pipe = Pipeline([
('scaler', StandardScaler()),
('clf', RandomForestClassifier(random_state=42)),
])
# 超参数搜索
param_grid = {
'clf__n_estimators': [100, 200],
'clf__max_depth': [None, 5, 10],
'clf__min_samples_leaf': [1, 2],
}
grid = GridSearchCV(pipe, param_grid, cv=5, scoring='roc_auc', n_jobs=-1, verbose=1)
grid.fit(X_train, y_train)
print(f"Best params: {grid.best_params_}")
print(f"CV ROC AUC: {grid.best_score_:.4f}")
# 测试集评估
y_pred = grid.predict(X_test)
y_prob = grid.predict_proba(X_test)[:, 1]
print(classification_report(y_test, y_pred, target_names=['malignant', 'benign']))
print(f"Test ROC AUC: {roc_auc_score(y_test, y_prob):.4f}")
# 特征重要性(从 Pipeline 中取出 clf)
importances = grid.best_estimator_['clf'].feature_importances_
top_features = np.argsort(importances)[-5:][::-1]
print("Top 5 features:", top_features)
最佳实践
始终在 Pipeline 内做预处理,而非手动拆分: 在 Pipeline 外对整个数据集做 fit_transform,再分训练测试集,会导致测试集信息泄漏到 Scaler 中,使评估结果过于乐观。
# 错误:先 fit scaler 再分割,测试集信息泄漏
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X) # 使用了测试集的均值/方差
X_train, X_test = train_test_split(X_scaled)
# 正确:先分割,再在 Pipeline 内 fit
X_train, X_test = train_test_split(X)
pipe = Pipeline([('scaler', StandardScaler()), ('clf', clf)])
pipe.fit(X_train, y_train)
pipe.predict(X_test)
固定 random_state 保证可复现性: 所有带随机性的操作(分割、模型初始化)都传入 random_state=42,确保实验结果可复现和对比。
类别不平衡时用分层抽样和合适指标: 不平衡数据集上 accuracy 是误导性指标,应用 ROC AUC、F1-macro 或 PR AUC;train_test_split(stratify=y) 保证训练/测试集类别比例一致。
用 cross_val_score 代替单次 train/test 分割评估: 单次分割结果受随机种子影响大,K 折交叉验证的均值 ± 标准差更可靠。
超参数调优优先用 RandomizedSearchCV 再细化: 参数空间大时(>30 个组合),先用 RandomizedSearchCV 找到大致区间,再用 GridSearchCV 在小范围精调,比直接全网格搜索节省 90% 时间。
使用 joblib.dump/load 持久化 Pipeline: 保存的 Pipeline 含 Scaler 参数,部署时直接 load 即可预测,无需重新 fit。
import joblib
joblib.dump(grid.best_estimator_, 'model.pkl')
model = joblib.load('model.pkl')
model.predict(X_test)
常见陷阱
陷阱:测试集泄漏到预处理步骤
现象: 交叉验证或测试集分数比实际部署效果好得多。
原因: 在 Pipeline 外对全量数据做了 fit_transform,导致 Scaler 的统计量包含了测试集的信息,测试集相当于被"见过"了。
解决: 所有预处理必须放进 Pipeline,只调用 Pipeline.fit(X_train) 和 Pipeline.transform(X_test)。
陷阱:GridSearchCV 内外套了不必要的 Scaler
现象: Pipeline 内已有 Scaler,外部又手动对全量数据做了归一化,导致双重标准化(零均值数据再次标准化后变形)。
原因: 不清楚 Pipeline 内部已经做了预处理。
解决: 检查 Pipeline 内已有的步骤,外部不要再做重复预处理。
陷阱:类别特征使用了 LabelEncoder
现象: 模型对类别特征赋予了大小关系(如 cat=0 < dog=1 < fish=2),线性模型或神经网络效果差。
原因: LabelEncoder 产生有序整数,暗示了不存在的大小关系;它只应用于目标变量 y,不应用于输入特征 X。
解决: 输入特征的类别编码使用 OneHotEncoder 或 OrdinalEncoder(仅当类别本身有序时)。
from sklearn.preprocessing import OrdinalEncoder, OneHotEncoder
# 错误:对类别特征用 LabelEncoder(产生错误的有序关系)
le = LabelEncoder()
X[:, 0] = le.fit_transform(X[:, 0])
# 正确:用 OneHotEncoder 在 Pipeline 内处理
pipe = Pipeline([
('enc', OneHotEncoder(handle_unknown='ignore')),
('clf', LogisticRegression()),
])
陷阱:max_iter 不足导致 ConvergenceWarning
现象: 输出 ConvergenceWarning: Lbfgs failed to converge,但模型看起来还能用。
原因: 求解器在 max_iter 次迭代内没有达到收敛条件,参数优化未完成,模型是次优解。
解决: 增大 max_iter(从 100 → 1000 → 10000),或先对数据做 StandardScaler 加速收敛,或换 solver。
参见
- PyTorch完全指南 — 深度学习,处理图像/文本/序列数据
- HuggingFace Transformers完全指南 — 预训练模型微调与推理
- Pandas完全指南 — 特征工程的数据处理基础
- 数据库设计规范 — 训练数据的存储与查询