MACHINE LEARNING · SCIKIT-LEARN · Python 机器学习标准库

Scikit-learn:一套 fit / predict 走天下

装上库,用统一 API 训练第一个分类器;再用 Pipeline + ColumnTransformer 把表格数据的预处理、交叉验证和调参串成一条流水线。这一页代码比概念多,全部可跑。

zsh — ~/ml-playground
$ python -m pip install scikit-learn
Successfully installed joblib-… numpy-… scikit-learn-1.9.1 scipy-…
>>> from sklearn.datasets import load_wine
>>> from sklearn.ensemble import RandomForestClassifier
>>> from sklearn.model_selection import train_test_split
>>> X_tr, X_te, y_tr, y_te = train_test_split(*load_wine(return_X_y=True), random_state=0)
>>> RandomForestClassifier(random_state=0).fit(X_tr, y_tr).score(X_te, y_te)
1.0 —— fit 训练、score 打分,全程各一行
本页目录

01

它是什么:经典机器学习的「标准库」

Scikit-learn 建在 NumPy / SciPy 之上,把十几年的经典机器学习算法——线性模型、决策树、随机森林、SVM、聚类、降维——统一成同一套 API:构造 → fit 训练 → predict / transform 使用 → score 打分。它从 2007 年一个 Google Summer of Code 项目起步,由法国国家信息与自动化研究院(Inria)等机构带领社区维护至今,是 Python 机器学习事实上的标准起点。

「统一」是它最大的价值:换模型只换一两行代码;Pipeline 能把预处理和模型串成一个对象;GridSearchCV 能对整条管道统一调参。学的是一套接口,用到的是整个算法库。

当前稳定版
1.9.1(2026-09 发布,以官网为准)
许可证
BSD-3,商用项目可放心集成
语言
Python(热点代码用 Cython 编译加速)
运行依赖
NumPy、SciPy、joblib、threadpoolctl
Python 版本
较新版本要求 3.11+(以安装页为准)
GPU
不支持,经典 ML 在 CPU 上就够快
不做的事
深度学习、强化学习请用 PyTorch / TensorFlow
名字来历
SciPy Toolkit(scikit)系列之一,learn 最出名
什么时候选它:数据是一张表格(数据库导出、CSV、Excel),任务是回归 / 分类 / 聚类 / 降维,样本量几千到几百万——scikit-learn 几乎总是第一选择。图像、语音、长文本的端到端深度学习则交给 PyTorch 或 TensorFlow。

02

安装:一条 pip,或者一条 conda

官方推荐装进虚拟环境。二进制轮子直接下载安装,不需要 C 编译器,连依赖一起装好。

Terminal
# 建独立环境(scikit-learn 1.9 要 Python 3.11+)
python3 -m venv .venv
source .venv/bin/activate       # Windows: .venv\Scripts\activate

python -m pip install scikit-learn

# 已装过,升级到最新:
python -m pip install -U scikit-learn
会自动带上 numpy、scipy、joblib。装完 import sklearn 验证。
别用 sudo pip 往系统 Python 装包:会污染系统依赖,升级还可能弄坏系统工具。永远在虚拟环境里 python -m pip install;Windows 下若 pip 装不上,优先换 conda。

03

快速上手:十行以内的第一个分类器

用内置的红酒数据集(178 条样本、13 个化学特征、3 个品种)走一次完整流程。注意每一行的分工:载入、切分、训练、打分,各占一两行。

first_clf.py
from sklearn.datasets import load_wine
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier

X, y = load_wine(return_X_y=True)     # 数据:直接拿到 numpy 数组

X_tr, X_te, y_tr, y_te = train_test_split(
    X, y, test_size=0.25, random_state=0, stratify=y)

clf = RandomForestClassifier(random_state=0)
clf.fit(X_tr, y_tr)                   # 训练:一行
print(clf.score(X_te, y_te))          # 评分:还是一行,这份数据能到 1.0
print(clf.predict(X_te[:3]))          # 预测新样本的类别
  • 01

    载入数据

    load_wine() 一行拿到。return_X_y=True 直接返回特征矩阵 X 和标签 y,不绕弯。

  • 02

    切分并分层

    train_test_split 留出 25% 当测试集;stratify=y 让两份数据的类别比例保持一致,小数据集必加。

  • 03

    fit:所有学习的入口

    sklearn 里任何模型都这样用:先构造(超参在括号里),再 fit。换模型就是换这两行。

  • 04

    score / predict

    score 给出测试集默认指标(分类是准确率);predict 输出具体预测。这一步之后才谈调参。

想让第一个分类器立刻变强:把 RandomForestClassifier 换成 SVC 或 LogisticRegression,其余一行不动。这就是统一 API 的甜头,下一节展开。

04

核心概念:统一 API、数据集、Pipeline、调参

统一 API:换模型只换一行

sklearn 把每个模型都做成「估计器(estimator)」类,接口完全一致。想比较三个模型?一个 for 循环就够,不用读三份文档:

同一个循环,三种模型
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
from sklearn.svm import SVC

for model in [LogisticRegression(max_iter=1000),
              RandomForestClassifier(random_state=0),
              SVC()]:
    model.fit(X_tr, y_tr)              # 同一个 fit
    print(model.__class__.__name__,
          model.score(X_te, y_te))     # 同一个 score

这也是学习方法论:先跑通最简单的逻辑回归当基线,再逐个换更强的模型比较——成本只剩一行 import。

fit(X, y)
学习:从数据估计参数。监督模型要传标签 y;转换器只吃 X(学均值、方差这类统计量)。
predict(X)
预测:训练好的模型对新样本输出类别或数值。
transform(X)
变换:转换器专用,按 fit 学到的统计量改写数据。fit_transform 是两步合一步。
score(X, y)
打分:模型默认指标——分类给准确率,回归给 R²。想换指标用 metrics 模块。

内置数据集:load_*、fetch_*、make_*

三组前缀记牢:load_ 玩具数据随包自带;fetch_ 真实数据首次运行才下载;make_ 按需合成数据。

datasets 常用入口
from sklearn import datasets

iris   = datasets.load_iris()          # 150x4 鸢尾花三分类
digits = datasets.load_digits()        # 1797 个 8x8 手写数字
wine   = datasets.load_wine()          # 178x13 红酒三分类

# 回归练习用加州房价:20640 条 x 8 特征,首次运行联网下载
housing = datasets.fetch_california_housing()

# 旧教程里的 load_boston 已在 1.2 版被移除(伦理问题),别再用
Xs, ys = datasets.make_classification(n_samples=1000, random_state=0)

load_wine() 不带 return_X_y 时返回 Bunch 对象,用 .data、.target、.feature_names 取内容——探索数据时这个形态更好用。

预处理与 Pipeline:transformer 串成一条线

另一类对象叫「转换器(transformer)」:提供 fit(学参数,如均值方差)和 transform(应用变换)。StandardScaler、OneHotEncoder、SimpleImputer 都是。把转换器和模型装进 Pipeline,一次 fit 全部按序执行:

pipeline_demo.py
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression

pipe = Pipeline([
    ("scaler", StandardScaler()),        # 第一步:标准化
    ("model",  LogisticRegression()),    # 第二步:模型
])

pipe.fit(X_tr, y_tr)      # 一次调用:先 fit 缩放,再训练模型
pipe.score(X_te, y_te)    # 评分时同样的顺序自动重放

为什么非要装管道?两个理由:防泄漏——缩放参数只在训练折上 fit,交叉验证时每折自动重做;可部署——管道是一个整体,保存、加载、上线都只搬一个对象,不会漏掉某个预处理步骤。

交叉验证与调参:GridSearchCV 一件套

cross_val_score 五折验证看泛化;GridSearchCV 穷举参数组合并内置交叉验证。对管道调参时,用双下划线定位深处的参数:

对整条管道调参
from sklearn.model_selection import cross_val_score, GridSearchCV

print(cross_val_score(pipe, X_tr, y_tr, cv=5).mean().round(3))

param_grid = {"model__C": [0.1, 1, 10]}
#          model 这一步的 C 参数 —— 双下划线 = 「走进去」

grid = GridSearchCV(pipe, param_grid, cv=5, n_jobs=-1)
grid.fit(X_tr, y_tr)
print(grid.best_params_, grid.best_score_.round(3))

n_jobs=-1 让所有 CPU 核一起算。搜完的 grid 本身就是训练好的最佳模型,直接 grid.score(X_te, y_te) 做终评。参数空间一大,网格组合数会指数爆炸——那时换 RandomizedSearchCV:同样参数下随机采样固定次数(n_iter),往往花 1/10 的时间找到差不多好的组合。完整的实战组合见第 06 节。

05

速查表:核心类、预处理、模型选择、数据集

下面这块表格能搜。忘了类名,直接搜 编码、交叉验证、聚类 之类的词。

类(sklearn.xxx)用途
linear_model.LinearRegression线性回归,回归的第一基线
linear_model.LogisticRegression线性分类器,输出概率
ensemble.RandomForestClassifier随机森林分类,默认强基线
ensemble.RandomForestRegressor随机森林回归
ensemble.HistGradientBoostingClassifier直方图加速的梯度提升,大数据集首选
svm.SVC支持向量机分类,小样本高维强
neighbors.KNeighborsClassifierK 近邻投票
naive_bayes.MultinomialNB多项朴素贝叶斯,文本分类常客
cluster.KMeansK 均值聚类(无监督)
decomposition.PCA主成分降维(无监督)
pipeline.Pipeline把预处理与模型串成一个对象
compose.ColumnTransformer按列分派不同 transformer

06

表格数据实战:数值列 + 类别列的规范全流程

真实业务数据几乎都是「数值列 + 类别列 + 缺失值」。下面用合成数据演示规范写法:ColumnTransformer 分列处理 → Pipeline 整体串联 → 交叉验证 → 网格调参 → 测试集终评。依赖 pandas,一条 pip install pandas 即可,代码可整体复制运行。

第一步:造一张「脏」表

tabular_pipeline.py · 数据准备
import numpy as np
import pandas as pd
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split, cross_val_score, GridSearchCV

rng = np.random.default_rng(42)
n = 600
df = pd.DataFrame({
    "age":    rng.integers(18, 70, n).astype(float),
    "income": rng.normal(6000, 2000, n).round(2),
    "city":   rng.choice(["北京", "上海", "广州", "深圳"], n),
    "device": rng.choice(["ios", "android", "web"], n),
})
df.loc[df.sample(frac=0.10, random_state=0).index, "device"] = np.nan
df.loc[df.sample(frac=0.05, random_state=1).index, "income"] = np.nan

第二步:目标变量与分列预处理器

tabular_pipeline.py · ColumnTransformer
# 目标:与特征相关的规则 + 噪声,模拟真实标签
filled = df["income"].fillna(df["income"].median())
logit = (filled - 6000) / 1500 + (df["city"] == "上海") * 0.8
y = (logit + rng.normal(0, 1, n) > 0.8).astype(int)

num_cols = ["age", "income"]
cat_cols = ["city", "device"]

preprocess = ColumnTransformer(transformers=[
    ("num", Pipeline([
        ("impute", SimpleImputer(strategy="median")),
        ("scale",  StandardScaler())]), num_cols),
    ("cat", Pipeline([
        ("impute", SimpleImputer(strategy="most_frequent")),
        ("onehot", OneHotEncoder(handle_unknown="ignore"))]), cat_cols),
])

clf = Pipeline([("prep", preprocess),
                ("model", RandomForestClassifier(random_state=0))])

第三步:交叉验证、调参、终评

tabular_pipeline.py · 训练与评估
X_tr, X_te, y_tr, y_te = train_test_split(
    df, y, test_size=0.2, random_state=42, stratify=y)

# 交叉验证:整条管道(含填充、缩放、编码)每折重新 fit,无泄漏
cv = cross_val_score(clf, X_tr, y_tr, cv=5)
print(cv.mean().round(3), cv.std().round(3))

# 网格调参:双下划线直达管道深处的模型参数
param_grid = {"model__n_estimators": [200, 500],
              "model__max_depth": [None, 8]}
search = GridSearchCV(clf, param_grid, cv=5, n_jobs=-1)
search.fit(X_tr, y_tr)
print(search.best_params_)

# 测试集终评(只做一次);顺手看 onehot 展开后的特征名
print(round(search.score(X_te, y_te), 3))
names = search.best_estimator_.named_steps["prep"].get_feature_names_out()
print(list(names)[:6])
预期输出(scikit-learn 1.9.1 实测):交叉验证 0.769 ± 0.030;最佳参数 {'model__max_depth': None, 'model__n_estimators': 500};测试集 0.767;展开后的特征名形如 num__age、cat__city_上海——前缀就是管道里的步骤名,一眼能对上来源。
这段骨架值得背下来:数值列「填充 → 缩放」、类别列「填充 → 独热」,ColumnTransformer 合流,Pipeline 接模型——这是 sklearn 处理表格数据的标准姿势。换成自己的数据,只需改 num_cols / cat_cols 和模型那两行。

07

避坑:四个最常见的翻车点

坑一:预处理泄漏——在全量数据上先 fit

「先 scaler 全量 fit,再切分」是最高频的错误:测试集的均值方差混进了训练。sklearn 的解法就是把预处理装进 Pipeline / ColumnTransformer,让 cross_val_score 每折自己重新 fit 转换器。

错误 vs 正确
# 错:全量数据先标准化,测试集信息已泄漏
X_scaled = StandardScaler().fit_transform(X)

# 对:交给管道,分折处理
pipe = Pipeline([("s", StandardScaler()), ("m", SVC())])
cross_val_score(pipe, X, y, cv=5)

坑二:线上遇到没见过的类别

训练集里城市只有四个,上线后用户填了「杭州」——默认配置的 OneHotEncoder 会直接报错。加 handle_unknown="ignore",未知类别编码成全零行,预测照常进行。

同类问题:数值列也可能出现训练时没见过的极端值。SimpleImputer 与缩放器照常处理,但要在监控里盯住「未知类别占比」——占比突然升高,说明数据分布变了,该重训模型了。

坑三:忘了 stratify,小数据集切出偏差

178 条、3 类的红酒数据,若不分层随机切 25%,某一折可能几乎抽不到某一类。分类任务切分时一律带上 stratify=y,交叉验证则默认用 StratifiedKFold(分类器场景下 GridSearchCV 会自动启用)。

切分对比
# 不分层:小数据集可能切出「某类样本不足」的测试集
X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.25)

# 分层:两份数据的类别比例与全量一致,分类任务的默认写法
X_tr, X_te, y_tr, y_te = train_test_split(
    X, y, test_size=0.25, stratify=y)

坑四:保存的模型跨版本加载失败

Terminal
joblib.dump(clf, "model.joblib")
# 加载端 sklearn 版本不一致时,可能直接报错或行为变化
python -c "import sklearn; print(sklearn.__version__)"

joblib.dump 本质是 pickle,绑定了训练时的 sklearn 版本。上线前固定版本(requirements.txt 里写死 scikit-learn==x.y.z),升级前先用原版本导出预测结果做回归测试。

08

进阶方向与资源

sklearn 的文档质量是开源界的标杆,顺着官方资源走,比到处搜博客靠谱。

  • 官方用户指南——按算法分章,每章配示例代码,值得通读一遍。
  • 示例画廊——几百个可跑的官方示例,找「某模型怎么画图」先来这里。
  • GitHub 仓库——提 issue、看源码实现;Cython 热点代码也在里面。
  • scikit-learn MOOC——Inria 出品的免费系统课程,视频 + Notebook 练习。
  • imbalanced-learn——官方生态的类别不平衡扩展(过采样 / 欠采样),接口与 sklearn 兼容。
  • 书:《Hands-On Machine Learning with Scikit-Learn, Keras & TensorFlow》(Aurélien Géron)——第 1-2 部分正是 sklearn 的最佳配套读物。
下一步去哪:把第 06 节的骨架套到 Kaggle 的 Titanic 数据集上练一遍;表格数据想再进一步,学 HistGradientBoosting 与特征工程;想进入图像 / 文本的深度学习世界,去本站 TensorFlow 或 PyTorch 教程——那边的「训练循环」要自己写了。

09

收尾:照着勾一遍

0 / 5

已复制