Scikit-learn(sklearn)速查表
最后更新
加载并划分数据
在做任何事之前先留出测试集,并且只在最后才去看它。
| 任务 | 代码 |
|---|---|
| 导入划分函数 | from sklearn.model_selection import train_test_split |
| 从 DataFrame 取出特征和目标值 | X = df.drop(columns="target")
y = df["target"] |
| 以 pandas 格式加载内置数据集 | from sklearn.datasets import load_iris
X, y = load_iris(return_X_y=True, as_frame=True) |
| 生成用于实验的合成数据 | from sklearn.datasets import make_classification
X, y = make_classification(n_samples=500, n_features=8, random_state=0) |
| 按 80/20 划分训练集和测试集 | X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) |
| 两部分保持相同的类别比例 | train_test_split(X, y, test_size=0.2, stratify=y, random_state=42) |
| 训练集、验证集和测试集(60/20/20) | X_tmp, X_test, y_tmp, y_test = train_test_split(X, y, test_size=0.2, random_state=0)
X_train, X_val, y_train, y_val = train_test_split(X_tmp, y_tmp, test_size=0.25, random_state=0) |
特征预处理
只在训练数据上拟合转换器,然后用它转换两份数据。在测试数据上拟合会造成信息泄露。
| 任务 | 代码 |
|---|---|
| 导入 | from sklearn.preprocessing import StandardScaler, MinMaxScaler, OneHotEncoder, OrdinalEncoder |
| 缩放到均值 0、标准差 1 | scaler = StandardScaler()
X_train_s = scaler.fit_transform(X_train[["age", "income"]])
X_test_s = scaler.transform(X_test[["age", "income"]]) |
| 缩放到 0 至 1 的范围 | MinMaxScaler().fit_transform(X_train[["age", "income"]]) |
| 对类别做独热编码 | enc = OneHotEncoder(handle_unknown="ignore", sparse_output=False)
enc.fit_transform(X_train[["city"]]) |
| 把有序类别编码成数字 | OrdinalEncoder(categories=[["low", "mid", "high"]]).fit_transform([["mid"], ["high"]]) |
| 填充缺失值 | from sklearn.impute import SimpleImputer
SimpleImputer(strategy="median").fit_transform(X_train[["age", "income"]]) |
| 多项式特征和交互特征 | from sklearn.preprocessing import PolynomialFeatures
PolynomialFeatures(degree=2, include_bias=False).fit_transform(X_train[["age", "income"]]) |
| 输出 DataFrame 而不是数组 | scaler.set_output(transform="pandas") |
| 把文本标签转成整数 | from sklearn.preprocessing import LabelEncoder
LabelEncoder().fit_transform(["cat", "dog", "cat"]) |
选择模型
从简单的模型开始,把它的得分当作要超越的基准。
| 问题 | 先用 | 再试 |
|---|---|---|
| 预测数值(回归) | LinearRegression(), Ridge(alpha=1.0) | RandomForestRegressor(), HistGradientBoostingRegressor() |
| 预测类别(分类) | LogisticRegression(max_iter=1000) | RandomForestClassifier(), HistGradientBoostingClassifier() |
| 数据量小,相近的点标签相同 | KNeighborsClassifier(n_neighbors=5) | SVC(kernel="rbf") |
| 需要能读懂的规则 | DecisionTreeClassifier(max_depth=3) | RandomForestClassifier() |
| 对没有标签的行分组 | KMeans(n_clusters=3) | DBSCAN(eps=0.5) |
| 减少特征,便于绘图或提速 | PCA(n_components=2) | TSNE(n_components=2) |
| 找出异常的行 | IsolationForest(random_state=0) | LocalOutlierFactor() |
训练模型
每个估计器的用法都一样:先带上参数创建它,再调用 fit。
| 任务 | 代码 |
|---|---|
| 所有模型通用的写法 | model = LogisticRegression(max_iter=1000)
model.fit(X_train, y_train) |
| 线性回归 | from sklearn.linear_model import LinearRegression
LinearRegression() |
| 带正则化的线性回归 | from sklearn.linear_model import Ridge, Lasso
Ridge(alpha=1.0), Lasso(alpha=0.1) |
| 逻辑回归(分类) | from sklearn.linear_model import LogisticRegression
LogisticRegression(C=1.0, max_iter=1000) |
| k 近邻 | from sklearn.neighbors import KNeighborsClassifier
KNeighborsClassifier(n_neighbors=5) |
| 决策树 | from sklearn.tree import DecisionTreeClassifier
DecisionTreeClassifier(max_depth=3, random_state=0) |
| 随机森林 | from sklearn.ensemble import RandomForestClassifier
RandomForestClassifier(n_estimators=200, random_state=0) |
| 梯度提升,大数据上也很快 | from sklearn.ensemble import HistGradientBoostingClassifier
HistGradientBoostingClassifier(random_state=0) |
| 支持向量机 | from sklearn.svm import SVC
SVC(kernel="rbf", C=1.0) |
| 朴素贝叶斯 | from sklearn.naive_bayes import GaussianNB
GaussianNB() |
| 总是猜多数类的基准模型 | from sklearn.dummy import DummyClassifier
DummyClassifier(strategy="most_frequent") |
预测与查看模型
| 任务 | 代码 |
|---|---|
| 预测类别或数值 | y_pred = model.predict(X_test) |
| 正类的概率 | model.predict_proba(X_test)[:, 1] |
| 快速评分:准确率或 R² | model.score(X_test, y_test) |
| 线性模型的系数 | model.coef_, model.intercept_ |
| 树模型的特征重要性 | pd.Series(forest.feature_importances_, index=X_train.columns).sort_values() |
| 逐个打乱特征来计算重要性 | from sklearn.inspection import permutation_importance
permutation_importance(model, X_test, y_test, random_state=0).importances_mean |
| 模型已知的类别标签 | model.classes_ |
| 读取和修改参数 | model.get_params(), model.set_params(C=0.5) |
| 画出决策树 | from sklearn.tree import plot_tree
plot_tree(tree, filled=True, feature_names=list(X_train.columns)) |
分类评估指标
只看准确率会掩盖稀有类别上的错误,还要看精确率、召回率和混淆矩阵。
| 任务 | 代码 |
|---|---|
| 导入 | from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score |
| 准确率 | accuracy_score(y_test, y_pred) |
| 精确率、召回率和 F1 | precision_score(y_test, y_pred), recall_score(y_test, y_pred), f1_score(y_test, y_pred) |
| 多分类的 F1 | f1_score(y_test, y_pred, average="macro") |
| 每个类别的全部指标 | from sklearn.metrics import classification_report
print(classification_report(y_test, y_pred)) |
| 混淆矩阵 | from sklearn.metrics import confusion_matrix
confusion_matrix(y_test, y_pred) |
| 画出混淆矩阵 | from sklearn.metrics import ConfusionMatrixDisplay
ConfusionMatrixDisplay.from_estimator(model, X_test, y_test) |
| 根据概率计算 ROC AUC | from sklearn.metrics import roc_auc_score
roc_auc_score(y_test, model.predict_proba(X_test)[:, 1]) |
| 画出 ROC 曲线 | from sklearn.metrics import RocCurveDisplay
RocCurveDisplay.from_estimator(model, X_test, y_test) |
| 类别不平衡时的准确率 | from sklearn.metrics import balanced_accuracy_score
balanced_accuracy_score(y_test, y_pred) |
| 自定义判定阈值 | y_pred = (model.predict_proba(X_test)[:, 1] >= 0.3).astype(int) |
回归评估指标
误差指标的单位和目标值相同(越低越好)。R² 是被解释的方差比例(1 表示完美)。
| 任务 | 代码 |
|---|---|
| 导入 | from sklearn.metrics import mean_absolute_error, mean_squared_error, root_mean_squared_error, r2_score |
| 平均绝对误差 | mean_absolute_error(y_test, y_pred) |
| 均方误差及其平方根 | mean_squared_error(y_test, y_pred), root_mean_squared_error(y_test, y_pred) |
| R² 分数 | r2_score(y_test, y_pred) |
| 平均绝对百分比误差 | from sklearn.metrics import mean_absolute_percentage_error
mean_absolute_percentage_error(y_test, y_pred) |
| 画出预测值与真实值的对比图 | from sklearn.metrics import PredictionErrorDisplay
PredictionErrorDisplay.from_predictions(y_test, y_pred, kind="actual_vs_predicted") |
Pipeline
Pipeline 把预处理和模型串成一个估计器,这样交叉验证和网格搜索只会在训练折上拟合每一步。
| 任务 | 代码 |
|---|---|
| 导入 | from sklearn.pipeline import make_pipeline, Pipeline |
| 先缩放,再训练模型 | pipe = make_pipeline(StandardScaler(), LogisticRegression(max_iter=1000))
pipe.fit(X_train, y_train) |
| 给步骤自定义名称 | pipe = Pipeline([("scale", StandardScaler()), ("model", LogisticRegression(max_iter=1000))]) |
| 访问其中某一步 | pipe.named_steps["model"], pipe[-1] |
| 不同的列用不同的步骤 | from sklearn.compose import ColumnTransformer
pre = ColumnTransformer([
("num", StandardScaler(), ["age", "income"]),
("cat", OneHotEncoder(handle_unknown="ignore"), ["city"]),
]) |
| 把预处理和模型放进同一个对象 | model = make_pipeline(pre, RandomForestClassifier(random_state=0))
model.fit(X_train, y_train)
model.score(X_test, y_test) |
| 按类型选取列 | from sklearn.compose import make_column_selector
make_column_selector(dtype_include="number")(X_train) |
| 先填充缺失值,再缩放 | make_pipeline(SimpleImputer(strategy="median"), StandardScaler()) |
| 输出特征的名称 | pre.get_feature_names_out() |
交叉验证
交叉验证在多种划分上训练并评估模型,得到的估计比单个测试集更稳定。
| 任务 | 代码 |
|---|---|
| 导入 | from sklearn.model_selection import cross_val_score, cross_validate, KFold, StratifiedKFold |
| 在 5 折上评分 | scores = cross_val_score(pipe, X, y, cv=5)
scores.mean(), scores.std() |
| 选择评估指标 | cross_val_score(pipe, X, y, cv=5, scoring="f1_macro") |
| 打乱后再分折 | cv = KFold(n_splits=5, shuffle=True, random_state=0) |
| 每一折的类别比例相同 | cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=0) |
| 多个指标外加训练集得分 | cross_validate(pipe, X, y, cv=cv, scoring=["accuracy", "f1"], return_train_score=True) |
| 用折外数据为每一行做预测 | from sklearn.model_selection import cross_val_predict
cross_val_predict(pipe, X, y, cv=5) |
| 按分组分折、按时间顺序分折 | from sklearn.model_selection import GroupKFold, TimeSeriesSplit
GroupKFold(n_splits=5), TimeSeriesSplit(n_splits=5) |
| 所有可用的 scoring 名称 | from sklearn.metrics import get_scorer_names
get_scorer_names() |
网格搜索与调参
搜索会用交叉验证为每组参数训练模型,保留最好的一组,再用全部训练数据重新拟合。
| 任务 | 代码 |
|---|---|
| 导入 | from sklearn.model_selection import GridSearchCV, RandomizedSearchCV |
| 尝试所有组合 | grid = GridSearchCV(RandomForestClassifier(random_state=0), {"n_estimators": [50, 100], "max_depth": [None, 5]}, cv=5)
grid.fit(X_train, y_train) |
| 最佳参数及其得分 | grid.best_params_, grid.best_score_ |
| 使用最佳模型 | grid.best_estimator_.predict(X_test), grid.score(X_test, y_test) |
| 调整 Pipeline 中的某一步 | GridSearchCV(pipe, {"logisticregression__C": [0.1, 1, 10]}, cv=5).fit(X_train, y_train) |
| 从分布中随机抽取参数 | from scipy.stats import randint
search = RandomizedSearchCV(RandomForestClassifier(random_state=0), {"n_estimators": randint(50, 150)}, n_iter=5, cv=3, random_state=0)
search.fit(X_train, y_train) |
| 用上所有 CPU 核心 | GridSearchCV(pipe, {"logisticregression__C": [0.1, 1]}, cv=5, n_jobs=-1) |
| 把所有结果整理成表格 | pd.DataFrame(grid.cv_results_).sort_values("rank_test_score") |
聚类与降维
无监督模型只从 X 中学习。两者都依赖距离,所以要先缩放特征。
| 任务 | 代码 |
|---|---|
| k-means 聚类 | from sklearn.cluster import KMeans
km = KMeans(n_clusters=3, random_state=0)
labels = km.fit_predict(X) |
| 聚类中心和惯性 | km.cluster_centers_, km.inertia_ |
| 各个簇分得有多开 | from sklearn.metrics import silhouette_score
silhouette_score(X, labels) |
| 基于密度的聚类,噪声点为 -1 | from sklearn.cluster import DBSCAN
DBSCAN(eps=0.5, min_samples=5).fit_predict(X) |
| 投影到 2 个主成分 | from sklearn.decomposition import PCA
pca = PCA(n_components=2)
X_2d = pca.fit_transform(X) |
| 每个主成分解释的方差 | pca.explained_variance_ratio_ |
| 保留 95% 的方差 | PCA(n_components=0.95).fit_transform(X) |
scikit-learn 1.9:旧写法与现在的写法
从旧教程里复制来的代码,在 scikit-learn 1.9 中可能报错或发出警告。请改用 scikit-learn 1.9 这一列的写法。
| 任务 | scikit-learn 1.9 | 旧写法 |
|---|---|---|
| 均方根误差 | root_mean_squared_error(y_test, y_pred) | mean_squared_error(y_test, y_pred, squared=False) |
| 输出稠密的独热编码 | OneHotEncoder(sparse_output=False) | OneHotEncoder(sparse=False) |
| L1(lasso)逻辑回归 | LogisticRegression(l1_ratio=1, solver="liblinear") | LogisticRegression(penalty="l1", solver="liblinear") |
| 不带正则化的逻辑回归 | LogisticRegression(C=np.inf) | LogisticRegression(penalty=None) |
保存、加载与复现
| 任务 | 代码 |
|---|---|
| 保存训练好的模型或 Pipeline | import joblib
joblib.dump(model, "model.joblib") |
| 重新加载 | model = joblib.load("model.joblib") |
| 每次运行结果相同 | random_state=0 |
| 查看已安装的版本 | import sklearn
sklearn.__version__ |
一个真实机器学习流程背后的 scikit-learn 代码,按你编写的顺序排列:加载并划分数据、预处理、选择模型、训练和预测、评估结果、把各个步骤串成 Pipeline、交叉验证,再用网格搜索调参。每一行都是一段可以直接粘贴的短代码,外加一句说明它的作用。
scikit-learn 中的每个模型都共用同一套 API:fit 从训练数据中学习,predict 和 transform 应用学到的内容。这里的所有代码都基于 Coddy 运行的 scikit-learn 1.9 版本编写,用 X 表示特征,y 表示目标值。scikit-learn 处理的是 NumPy 数组和 pandas DataFrame,绘图部分请看 Matplotlib 速查表。刚开始学 Python?先从 Python 速查表看起。
Scikit-learn 速查表常见问题
这份 scikit-learn 速查表免费吗?
免费。这份 scikit-learn 速查表完全免费,无需注册。收藏起来,或者在浏览器里打印成 PDF,需要查 Pipeline、评估指标或网格搜索的具体写法时随时回来看。
sklearn 和 scikit-learn 是一回事吗?
pip install scikit-learn),而 sklearn 是你在代码里导入时用的名字(from sklearn.linear_model import LinearRegression)。sklearn 速查表和 scikit-learn 速查表讲的是同一件事。fit、transform 和 fit_transform 有什么区别?
fit 从数据中学习:缩放器学习每一列的均值,模型学习它的权重。transform 应用学到的内容,fit_transform 则一次完成这两步。在训练集上用 fit_transform,在测试集上只用 transform,否则测试数据就会泄露到训练中。Pipeline 会自动帮你处理这一点。需要对特征做缩放吗?
对于依赖距离或梯度的模型,需要:k 近邻、SVM、k-means、PCA,以及带正则化的线性回归和逻辑回归,在缩放后的数据上效果都更好。决策树、随机森林和梯度提升这类树模型则不需要缩放。把缩放器放进 Pipeline,确保它只在训练数据上拟合。
应该先用哪个 scikit-learn 模型?
LinearRegression,预测类别用 LogisticRegression。然后试试 RandomForestClassifier 或 HistGradientBoostingClassifier(或它们的回归版本),用交叉验证比较,再用 GridSearchCV 调优表现最好的那个。这份速查表对应哪个 scikit-learn 版本?
mean_squared_error 中的 squared=False、OneHotEncoder 中的 sparse=False,以及 LogisticRegression 的 penalty 参数,都列在旧写法表格里,旁边就是现在该怎么写。