Scikit-learn 核心概念 Scikit-learn 核心概念详解:代码实践与深入解析 本文将围绕以下几个核心概念展开: Estimators (估计器): Scikit-learn 的基石,模型、转换器都属于估计器。我们将深入理解估计器的通用接口,以及如何使用它们进行模型训练和预测。 Transformers (转换器): 用于数据预处理和特征工程。我们将学习如何使用转换器进行数据标准化、特征缩放、编码等操作,提升模型性能。 Pipelines (管道): 将多个估计器串联起来,构建机器学习工作流。我们将学习如何使用管道简化模型构建流程,避免数据泄露,并提高代码的可读性和可维护性。 Model Selection (模型选择): 选择最佳模型和超参数的关键步骤。
本文将围绕以下几个核心概念展开:
Estimators (估计器): Scikit-learn 的基石,模型、转换器都属于估计器。我们将深入理解估计器的通用接口,以及如何使用它们进行模型训练和预测。
Transformers (转换器): 用于数据预处理和特征工程。我们将学习如何使用转换器进行数据标准化、特征缩放、编码等操作,提升模型性能。
Pipelines (管道): 将多个估计器串联起来,构建机器学习工作流。我们将学习如何使用管道简化模型构建流程,避免数据泄露,并提高代码的可读性和可维护性。
Model Selection (模型选择): 选择最佳模型和超参数的关键步骤。我们将学习交叉验证、网格搜索等模型选择方法,以及如何使用它们来优化模型性能。
Datasets (数据集): Scikit-learn 内置数据集以及数据加载方式。我们将了解如何使用 Scikit-learn 提供的数据集进行模型训练和评估,以及如何加载自定义数据集。
Evaluation Metrics (评估指标): 衡量模型性能的关键工具。我们将学习分类、回归等不同任务的常用评估指标,以及如何在 Scikit-learn 中使用它们。
1. Estimators (估计器): 机器学习的基石
在 Scikit-learn 中,Estimator (估计器) 是一个核心概念,它指的是可以从数据中学习的对象。无论是用于模型训练的分类器、回归器,还是用于数据预处理的转换器,都属于估计器。
Estimators 的通用接口:
Scikit-learn 的强大之处在于其统一的 API 设计。所有估计器都遵循一套通用的接口,这使得用户可以轻松地学习和使用不同的算法。 最重要的两个接口方法是:
fit(X, y): 用于从训练数据 (X, y) 中学习模型参数。X 通常是特征矩阵,y 是目标变量(监督学习)。对于无监督学习,fit(X) 只需要特征矩阵 X。
predict(X): 用于使用已训练的模型对新数据 X 进行预测。对于分类任务,predict(X) 返回预测的类别标签;对于回归任务,返回预测的数值。
transform(X): 用于对数据 X 进行转换。只有 Transformers (转换器) 类型的估计器才具有 transform 方法,例如 StandardScaler、PCA 等。
fit_transform(X, y): 某些估计器(如转换器)同时提供 fit_transform 方法,它相当于先调用 fit(X, y) 再调用 transform(X). 这在某些情况下可以提高效率。
代码实践:使用 Estimator 进行分类
我们以一个简单的例子来演示如何使用 Estimator 进行分类。我们将使用 Scikit-learn 内置的 鸢尾花 (iris) 数据集,并使用 K近邻 (K-Nearest Neighbors, KNN) 分类器。
from sklearn.neighbors import KNeighborsClassifier from sklearn.model_selection import train_test_split from sklearn.datasets import load_iris from sklearn.metrics import accuracy_score # 1. 加载数据集 iris = load_iris() X, y = iris.data, iris.target # 2. 划分训练集和测试集 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42) # 3. 初始化 KNN 分类器 (Estimator) knn = KNeighborsClassifier(n_neighbors=3) # 4. 训练模型 (调用 fit 方法) knn.fit(X_train, y_train) # 5. 预测 (调用 predict 方法) y_pred = knn.predict(X_test) # 6. 评估模型性能 (使用评估指标) accuracy = accuracy_score(y_test, y_pred) print(f"KNN 分类器准确率: {accuracy:.2f}")
代码详解:
加载数据集: load_iris() 函数加载鸢尾花数据集,返回一个 Bunch 对象,包含数据和标签。
划分数据集: train_test_split() 函数将数据集划分为训练集和测试集,用于模型训练和评估。
初始化 KNN 分类器: KNeighborsClassifier(n_neighbors=3) 创建一个 KNN 分类器实例,n_neighbors 是 KNN 算法的超参数,这里设置为 3。knn 就是一个 Estimator 对象。
训练模型: knn.fit(X_train, y_train) 调用 fit 方法,使用训练数据 (X_train, y_train) 训练 KNN 模型。KNN 模型的训练过程主要是存储训练数据。
预测: knn.predict(X_test) 调用 predict 方法,使用训练好的 KNN 模型对测试集 X_test 进行预测,返回预测的类别标签 y_pred。
评估模型性能: accuracy_score(y_test, y_pred) 计算分类器的准确率,衡量模型在测试集上的性能。
Estimator 的核心思想:
封装性: Estimator 将机器学习算法封装成对象,隐藏了算法的具体实现细节,用户只需要关注如何使用 fit 和 predict 等通用接口。
一致性: 所有 Estimator 都遵循相同的接口,降低了学习成本,用户可以轻松地切换和比较不同的算法。
可扩展性: Scikit-learn 提供了丰富的 Estimator,用户也可以自定义 Estimator 来扩展库的功能。
2. Transformers (转换器): 数据预处理的利器
Transformers (转换器) 也是一种特殊的 Estimator,专门用于数据预处理和特征工程。它们的主要作用是将原始数据转换为更适合机器学习模型训练的形式。常见的转换器包括:
标准化 (Standardization): StandardScaler,将数据缩放到均值为 0,标准差为 1 的分布。
归一化 (Normalization): MinMaxScaler, MaxAbsScaler, RobustScaler 等,将数据缩放到指定的范围,例如 [0, 1] 或 [-1, 1]。
编码 (Encoding): OneHotEncoder, OrdinalEncoder, LabelEncoder 等,将类别特征转换为数值特征。
特征选择 (Feature Selection): SelectKBest, RFE, SelectFromModel 等,选择最重要的特征,降低数据维度。
降维 (Dimensionality Reduction): PCA, KernelPCA, TruncatedSVD 等,减少特征维度,去除冗余信息。
Transformers 的核心方法:
fit(X, y=None): 学习数据转换所需的参数,例如 StandardScaler 需要学习数据的均值和标准差。注意,有些转换器不需要目标变量 y。
transform(X): 使用 fit 方法学习到的参数对数据 X 进行转换,返回转换后的数据。
fit_transform(X, y=None): 先调用 fit(X, y) 再调用 transform(X).
代码实践:使用 Transformer 进行数据标准化
我们使用 StandardScaler 对鸢尾花数据集进行标准化处理。
from sklearn.preprocessing import StandardScaler from sklearn.model_selection import train_test_split from sklearn.datasets import load_iris import numpy as np # 1. 加载数据集 iris = load_iris() X, y = iris.data, iris.target # 2. 划分训练集和测试集 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42) # 3. 初始化 StandardScaler (Transformer) scaler = StandardScaler() # 4. 训练并转换训练数据 (fit_transform) X_train_scaled = scaler.fit_transform(X_train) # 5. 转换测试数据 (transform) X_test_scaled = scaler.transform(X_test) # 打印原始数据和标准化后的数据的均值和标准差 (仅训练集) print("原始训练数据均值 (每列):", np.mean(X_train, axis=0)) print("原始训练数据标准差 (每列):", np.std(X_train, axis=0)) print("标准化后训练数据均值 (每列):", np.mean(X_train_scaled, axis=0)) print("标准化后训练数据标准差 (每列):", np.std(X_train_scaled, axis=0))
代码详解:
初始化 StandardScaler: StandardScaler() 创建一个 StandardScaler 转换器实例。
训练并转换训练数据: scaler.fit_transform(X_train) 先使用训练数据 X_train 训练 StandardScaler,学习训练集每列特征的均值和标准差,然后使用学习到的参数对 X_train 进行标准化转换,得到 X_train_scaled。
转换测试数据: scaler.transform(X_test) 使用训练集学习到的均值和标准差,对测试集 X_test 进行标准化转换,得到 X_test_scaled。 注意:测试集只能使用训练集学习到的参数进行转换,避免数据泄露。
打印均值和标准差: 验证标准化效果。可以看到标准化后的训练数据均值接近 0,标准差接近 1。
Transformer 的重要性:
提升模型性能: 数据预处理可以提高模型的训练速度和泛化能力。例如,标准化可以避免特征尺度不一致导致模型训练不稳定。
处理不同类型数据: Transformer 可以处理不同类型的数据,例如类别特征、文本特征、图像特征等,使其能够被机器学习模型使用。
特征工程: Transformer 可以用于特征工程,例如通过多项式特征扩展、特征组合等方式创造新的特征,提升模型性能。
3. Pipelines (管道): 构建高效的机器学习工作流
Pipelines (管道) 是 Scikit-learn 中一个非常重要的概念,它允许我们将多个 Estimators (估计器) 串联起来,构建一个完整的机器学习工作流。管道的主要作用是:
简化工作流: 将数据预处理、特征工程、模型训练等步骤组合成一个单一的 Pipeline 对象,简化代码,提高可读性。
避免数据泄露: Pipeline 可以确保数据预处理步骤仅在训练集上学习参数,然后将这些参数应用于训练集、验证集和测试集,避免数据泄露,保证模型评估的可靠性。
方便模型部署: Pipeline 可以将整个机器学习流程打包成一个对象,方便模型部署和复用。
自动化参数调优: Pipeline 可以与模型选择工具(如 GridSearchCV)结合使用,自动化地进行超参数调优。
Pipeline 的核心思想:
Pipeline 对象接收一个 Estimator 列表作为输入,按照列表的顺序依次执行每个 Estimator 的 fit_transform (对于 Transformer) 或 fit (对于最后一个 Estimator) 和 transform (对于 Transformer) 或 predict (对于最后一个 Estimator) 方法。
代码实践:使用 Pipeline 构建分类工作流
我们使用 Pipeline 将 StandardScaler 和 KNeighborsClassifier 组合起来,构建一个包含数据标准化和 KNN 分类的完整工作流。
from sklearn.pipeline import Pipeline from sklearn.preprocessing import StandardScaler from sklearn.neighbors import KNeighborsClassifier from sklearn.model_selection import train_test_split from sklearn.datasets import load_iris from sklearn.metrics import accuracy_score # 1. 加载数据集 iris = load_iris() X, y = iris.data, iris.target # 2. 划分训练集和测试集 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42) # 3. 创建 Pipeline pipeline = Pipeline([ ('scaler', StandardScaler()), # 第一步:数据标准化 (Transformer) ('knn', KNeighborsClassifier(n_neighbors=3)) # 第二步:KNN 分类 (Estimator) ]) # 4. 训练 Pipeline (调用 fit 方法) pipeline.fit(X_train, y_train) # 5. 预测 (调用 predict 方法) y_pred = pipeline.predict(X_test) # 6. 评估模型性能 accuracy = accuracy_score(y_test, y_pred) print(f"Pipeline 分类器准确率: {accuracy:.2f}")
代码详解:
创建 Pipeline: Pipeline([ ... ]) 创建一个 Pipeline 对象,接收一个 Estimator 列表。每个 Estimator 以 (name, estimator) 的元组形式表示,name 是 Estimator 的名称,可以自定义,estimator 是 Estimator 对象实例。
('scaler', StandardScaler()): 命名为 'scaler' 的 StandardScaler 转换器。
('knn', KNeighborsClassifier(n_neighbors=3)): 命名为 'knn' 的 KNeighborsClassifier 分类器。
训练 Pipeline: pipeline.fit(X_train, y_train) 调用 Pipeline 对象的 fit 方法,它会依次执行以下操作:
对训练数据 X_train 调用 scaler.fit_transform(X_train, y_train),学习标准化参数并转换数据。
对转换后的训练数据调用 knn.fit(X_train_scaled, y_train),训练 KNN 模型。
预测: pipeline.predict(X_test) 调用 Pipeline 对象的 predict 方法,它会依次执行以下操作:
对测试数据 X_test 调用 scaler.transform(X_test),使用训练集学习到的标准化参数转换测试数据。
对转换后的测试数据调用 knn.predict(X_test_scaled),使用训练好的 KNN 模型进行预测。
Pipeline 的优势:
代码简洁: Pipeline 将多个步骤封装成一个对象,代码更简洁易懂。
避免数据泄露: Pipeline 保证数据预处理步骤仅在训练集上学习参数,避免数据泄露。
参数访问: 可以使用 pipeline.named_steps 属性访问 Pipeline 中的 Estimator,并使用 pipeline.named_steps['name'].get_params() 获取 Estimator 的参数。例如,pipeline.named_steps['knn'].get_params() 可以获取 KNN 分类器的参数。
4. Model Selection (模型选择): 找到最佳模型
Model Selection (模型选择) 是机器学习流程中至关重要的一步,它旨在选择最佳的模型和超参数,以获得最佳的泛化性能。Scikit-learn 提供了丰富的工具用于模型选择,包括:
交叉验证 (Cross-validation): 评估模型泛化性能的可靠方法,例如 KFold, StratifiedKFold, cross_val_score 等。
网格搜索 (GridSearchCV): 用于超参数调优的常用方法,通过穷举搜索指定的超参数组合,找到最佳的超参数。
随机搜索 (RandomizedSearchCV): 超参数搜索的另一种方法,在指定的超参数空间中随机采样参数组合进行搜索,效率更高,尤其适用于高维超参数空间。
学习曲线 (Learning Curve): 可视化模型在不同训练集大小下的性能,帮助判断模型是否欠拟合或过拟合。
验证曲线 (Validation Curve): 可视化模型在不同超参数取值下的性能,帮助选择最佳超参数。
代码实践:使用 GridSearchCV 进行超参数调优
我们使用 GridSearchCV 对 Pipeline 中的 KNN 分类器的 n_neighbors 超参数进行调优。
from sklearn.pipeline import Pipeline from sklearn.preprocessing import StandardScaler from sklearn.neighbors import KNeighborsClassifier from sklearn.model_selection import train_test_split, GridSearchCV from sklearn.datasets import load_iris from sklearn.metrics import accuracy_score # 1. 加载数据集 iris = load_iris() X, y = iris.data, iris.target # 2. 划分训练集和测试集 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42) # 3. 创建 Pipeline pipeline = Pipeline([ ('scaler', StandardScaler()), ('knn', KNeighborsClassifier()) # 注意这里 KNN 初始化时不需要指定 n_neighbors ]) # 4. 定义超参数网格 param_grid = { 'knn__n_neighbors': [3, 5, 7, 9, 11] # 'knn__n_neighbors' 表示 KNN 分类器的 n_neighbors 参数 } # 5. 创建 GridSearchCV 对象 grid_search = GridSearchCV(pipeline, param_grid, cv=5, scoring='accuracy') # cv=5 表示 5 折交叉验证,scoring='accuracy' 表示评估指标为准确率 # 6. 训练 GridSearchCV (调用 fit 方法) grid_search.fit(X_train, y_train) # 7. 获取最佳模型和最佳超参数 best_pipeline = grid_search.best_estimator_ best_params = grid_search.best_params_ # 8. 使用最佳模型进行预测 y_pred = best_pipeline.predict(X_test) # 9. 评估最佳模型性能 accuracy = accuracy_score(y_test, y_pred) print(f"最佳 Pipeline 分类器准确率: {accuracy:.2f}") print(f"最佳超参数: {best_params}")
代码详解:
定义超参数网格: param_grid 是一个字典,定义了要搜索的超参数及其取值范围。 注意:超参数名称需要使用 estimator_name__parameter_name 的格式,例如 'knn__n_neighbors' 表示 Pipeline 中名为 'knn' 的 Estimator 的 n_neighbors 参数。
创建 GridSearchCV 对象: GridSearchCV(pipeline, param_grid, cv=5, scoring='accuracy') 创建一个 GridSearchCV 对象。
pipeline: 要进行超参数调优的 Pipeline 对象。
param_grid: 超参数网格。
cv=5: 使用 5 折交叉验证。
scoring='accuracy': 使用准确率作为评估指标。
训练 GridSearchCV: grid_search.fit(X_train, y_train) 调用 GridSearchCV 对象的 fit 方法,它会执行以下操作:
对于 param_grid 中定义的每种超参数组合,使用交叉验证评估 Pipeline 的性能。
选择平均交叉验证得分最高的超参数组合作为最佳超参数。
使用最佳超参数在整个训练集上重新训练 Pipeline。
获取最佳模型和最佳超参数:
grid_search.best_estimator_: 获取训练好的最佳 Pipeline 对象。
grid_search.best_params_: 获取最佳超参数组合。
Model Selection 的重要性:
找到最佳模型: 模型选择可以帮助我们选择最适合当前任务的模型,提高模型性能。
避免过拟合: 通过交叉验证等方法,模型选择可以评估模型的泛化能力,避免模型在训练集上表现很好,但在测试集上表现很差的过拟合现象。
优化模型性能: 超参数调优可以找到模型的最佳超参数组合,进一步提升模型性能。
5. Datasets (数据集): 数据的来源
Scikit-learn 提供了许多内置的 Datasets (数据集),方便用户进行模型训练和算法测试。这些数据集主要分为两类:
玩具数据集 (Toy datasets): 小型数据集,用于快速演示和算法测试,例如 iris, boston_housing, digits, wine 等。
真实世界数据集 (Real-world datasets): 较大规模的数据集,用于更真实的场景模拟,例如 olivetti_faces, lfw_people, 20newsgroups 等。
加载数据集:
Scikit-learn 提供了一系列函数用于加载数据集,例如:
load_iris(): 加载鸢尾花数据集。
load_boston(): 加载波士顿房价数据集。
load_digits(): 加载手写数字数据集。
load_wine(): 加载葡萄酒数据集。
fetch_olivetti_faces(): 下载 Olivetti 人脸数据集。
fetch_lfw_people(): 下载 LFW 人脸数据集。
fetch_20newsgroups(): 下载 20 新闻组数据集。
数据集的结构:
Scikit-learn 的数据集通常以 Bunch 对象的形式返回,它类似于 Python 字典,包含以下键:
data: 特征矩阵,NumPy array 格式。
target: 目标变量,NumPy array 格式。
feature_names: 特征名称列表。
target_names: 目标变量名称列表(分类任务)。
DESCR: 数据集描述信息。
filename: 数据集文件路径(某些数据集)。
代码实践:加载并查看鸢尾花数据集
from sklearn.datasets import load_iris # 加载鸢尾花数据集 iris = load_iris() # 查看数据集信息 print("数据集名称:", iris.DESCR[:200] + "...") # 打印部分描述信息 print("特征名称:", iris.feature_names) print("目标变量名称:", iris.target_names) print("特征矩阵形状:", iris.data.shape) print("目标变量形状:", iris.target.shape) print("数据集类型:", type(iris))
代码详解:
load_iris(): 加载鸢尾花数据集,返回一个 Bunch 对象 iris.
iris.DESCR, iris.feature_names, iris.target_names, iris.data.shape, iris.target.shape, type(iris): 访问 Bunch 对象的属性,查看数据集的描述信息、特征名称、目标变量名称、数据形状和对象类型。
自定义数据集加载:
除了 Scikit-learn 内置数据集,我们也可以加载自定义数据集,例如从 CSV 文件、文本文件、数据库等加载数据。可以使用 Pandas 库读取数据,然后将其转换为 NumPy array 格式,即可用于 Scikit-learn 模型训练。
6. Evaluation Metrics (评估指标): 衡量模型性能
Evaluation Metrics (评估指标) 用于衡量机器学习模型的性能。不同的任务类型需要使用不同的评估指标。Scikit-learn 提供了丰富的评估指标,主要分为以下几类:
分类指标 (Classification metrics): 用于评估分类模型的性能,例如:
accuracy_score: 准确率。
precision_score: 精确率。
recall_score: 召回率。
f1_score: F1 值。
roc_auc_score: ROC AUC 曲线下面积。
classification_report: 分类报告,包含精确率、召回率、F1 值等指标。
confusion_matrix: 混淆矩阵。
回归指标 (Regression metrics): 用于评估回归模型的性能,例如:
mean_squared_error: 均方误差 (MSE)。
mean_absolute_error: 平均绝对误差 (MAE)。
r2_score: R 平方值 (决定系数)。
聚类指标 (Clustering metrics): 用于评估聚类模型的性能,例如:
silhouette_score: 轮廓系数。
calinski_harabasz_score: Calinski-Harabasz 指数。
davies_bouldin_score: Davies-Bouldin 指数。
代码实践:使用分类评估指标
我们使用 classification_report 和 confusion_matrix 评估 KNN 分类器的性能。
from sklearn.neighbors import KNeighborsClassifier from sklearn.model_selection import train_test_split from sklearn.datasets import load_iris from sklearn.metrics import accuracy_score, classification_report, confusion_matrix # 1. 加载数据集 iris = load_iris() X, y = iris.data, iris.target # 2. 划分训练集和测试集 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42) # 3. 初始化 KNN 分类器 knn = KNeighborsClassifier(n_neighbors=3) # 4. 训练模型 knn.fit(X_train, y_train) # 5. 预测 y_pred = knn.predict(X_test) # 6. 评估模型性能 accuracy = accuracy_score(y_test, y_pred) print(f"KNN 分类器准确率: {accuracy:.2f}") # 7. 打印分类报告 print("\n分类报告:") print(classification_report(y_test, y_pred)) # 8. 打印混淆矩阵 print("\n混淆矩阵:") print(confusion_matrix(y_test, y_pred))
代码详解:
classification_report(y_test, y_pred): 生成分类报告,包含每个类别的精确率、召回率、F1 值和支持度 (样本数量)。
confusion_matrix(y_test, y_pred): 生成混淆矩阵,用于可视化模型在每个类别上的预测结果。混淆矩阵的对角线元素表示模型预测正确的样本数量,非对角线元素表示模型预测错误的样本数量。
选择合适的评估指标:
选择合适的评估指标取决于具体的任务和业务目标。例如,在不平衡数据集中,准确率可能不是一个好的指标,应该考虑使用精确率、召回率、F1 值或 ROC AUC 等指标。