3.1 分类任务 Scikit-learn 实践应用领域:分类任务详解 Scikit-learn (也称为 sklearn) 是 Python 中最受欢迎的机器学习库之一。它提供了丰富的工具和算法,涵盖了分类、回归、聚类、降维、模型选择和预处理等多个方面。在众多应用领域中,分类任务 是机器学习的核心任务之一,而 Scikit-learn 在分类任务中表现出色,提供了多种高效且易于使用的分类算法和评估工具。 3.1 分类任务详解 3.1.1 分类任务概述 分类任务是机器学习中的一种监督学习任务,其目标是根据已知的特征将数据样本划分到预定义的类别中。简单来说,分类模型学习从输入特征到离散类别标签的映射关系。 分类任务的常见应用场景: 垃圾邮件检测: 将邮件分为“垃圾邮件”和“非垃圾邮件”两类。
Scikit-learn (也称为 sklearn) 是 Python 中最受欢迎的机器学习库之一。它提供了丰富的工具和算法,涵盖了分类、回归、聚类、降维、模型选择和预处理等多个方面。在众多应用领域中,分类任务 是机器学习的核心任务之一,而 Scikit-learn 在分类任务中表现出色,提供了多种高效且易于使用的分类算法和评估工具。
3.1.1 分类任务概述
分类任务是机器学习中的一种监督学习任务,其目标是根据已知的特征将数据样本划分到预定义的类别中。简单来说,分类模型学习从输入特征到离散类别标签的映射关系。
分类任务的常见应用场景:
垃圾邮件检测: 将邮件分为“垃圾邮件”和“非垃圾邮件”两类。
图像识别: 识别图像中的物体,例如将图片分类为“猫”、“狗”、“汽车”等。
医学诊断: 根据患者的症状和检查结果,判断患者是否患有某种疾病。
客户流失预测: 预测哪些客户可能会流失,以便进行挽留。
情感分析: 分析文本的情感倾向,例如将评论分为“正面”、“负面”或“中性”。
分类任务的类型:
二分类: 将数据样本分为两个类别,例如“是/否”、“正/负”、“0/1”。
多分类: 将数据样本分为两个以上的类别,例如“猫/狗/鱼”、“红/绿/蓝”。
多标签分类: 一个数据样本可以同时属于多个类别,例如一篇新闻可以同时属于“政治”和“经济”类别。
3.1.2 Scikit-learn 中的分类算法
Scikit-learn 提供了丰富的分类算法,涵盖了各种不同的模型类型,包括:
线性模型:
逻辑回归 (Logistic Regression): 用于二分类和多分类,通过 sigmoid 函数将线性模型的输出映射到概率值。
支持向量机 (Support Vector Machines, SVM): 通过寻找最优超平面进行分类,在高维空间中表现出色。
线性判别分析 (Linear Discriminant Analysis, LDA): 假设每个类别的数据都服从高斯分布,通过寻找最优投影方向进行分类。
岭回归分类器 (RidgeClassifier): 基于岭回归的分类器,适用于特征之间存在多重共线性的情况。
被动攻击分类器 (PassiveAggressiveClassifier): 一种在线学习算法,适用于处理大规模数据流。
感知器 (Perceptron): 最简单的神经网络模型,用于线性可分数据的二分类。
基于树的模型:
决策树 (Decision Tree): 通过树状结构进行分类,易于理解和解释。
随机森林 (Random Forest): 集成学习方法,通过构建多个决策树并进行投票来提高分类性能和鲁棒性。
梯度提升树 (Gradient Boosting Trees, GBT): 另一种集成学习方法,通过迭代地训练弱学习器 (通常是决策树) 来构建强分类器。
极端梯度提升 (Extreme Gradient Boosting, XGBoost): 梯度提升树的一种高效实现,在各种机器学习竞赛中表现出色。
轻量级梯度提升机 (LightGBM): 另一种高效的梯度提升框架,特别适用于大规模数据集。
CatBoost: 由 Yandex 开发的梯度提升算法,在处理类别特征方面具有优势。
最近邻算法:
朴素贝叶斯 (Naive Bayes):
高斯朴素贝叶斯 (Gaussian Naive Bayes): 假设特征服从高斯分布。
多项式朴素贝叶斯 (Multinomial Naive Bayes): 适用于离散特征,例如文本分类中的词频。
伯努利朴素贝叶斯 (Bernoulli Naive Bayes): 适用于二元特征,例如文档中词语是否出现。
补充朴素贝叶斯 (Complement Naive Bayes): 对不平衡数据集的朴素贝叶斯算法的改进。
神经网络模型:
3.1.3 分类模型的评估指标
选择合适的评估指标对于评估分类模型的性能至关重要。Scikit-learn 提供了多种评估指标,常用的包括:
准确率 (Accuracy): 分类正确的样本数占总样本数的比例。适用于类别分布均衡的数据集。
精确率 (Precision): 预测为正例的样本中,真正为正例的比例。关注模型预测正例的准确性。
召回率 (Recall): 真正为正例的样本中,被模型预测为正例的比例。关注模型对正例的识别能力。
F1 值 (F1-score): 精确率和召回率的调和平均值,综合考虑了精确率和召回率。
AUC-ROC 曲线: 受试者工作特征 (Receiver Operating Characteristic) 曲线下的面积。用于评估二分类模型在不同阈值下的性能,尤其适用于不平衡数据集。
混淆矩阵 (Confusion Matrix): 用于可视化分类结果,展示模型在各个类别上的预测情况。
分类报告 (Classification Report): Scikit-learn 提供的便捷工具,包含精确率、召回率、F1 值和支持度 (每个类别的样本数量) 等指标。
3.1.4 分类任务的基本流程
使用 Scikit-learn 进行分类任务通常包括以下步骤:
数据准备:
加载数据集。
数据探索和可视化 (可选)。
数据预处理:
特征工程 (特征选择、特征构建)。
数据清洗 (处理缺失值、异常值)。
特征缩放 (标准化、归一化)。
类别编码 (对于类别特征)。
划分训练集和测试集。
模型选择:
根据任务需求和数据特点选择合适的分类算法。
考虑模型的复杂度、可解释性、训练速度和预测性能等因素。
模型训练:
使用训练集数据训练选定的分类模型。
设置模型超参数 (可选)。
模型评估:
使用测试集数据评估模型的性能。
选择合适的评估指标。
分析评估结果,例如混淆矩阵、分类报告、AUC-ROC 曲线等。
模型优化 (可选):
超参数调优 (例如使用 GridSearchCV 或 RandomizedSearchCV)。
特征选择或特征工程改进。
尝试不同的模型或模型组合。
模型部署 (可选):
接下来,我们将通过具体的代码示例,详细介绍如何使用 Scikit-learn 进行分类任务。我们将涵盖数据准备、模型选择、模型训练、模型评估和模型优化的各个环节。
3.2.1 数据准备
我们使用 Scikit-learn 内置的 iris (鸢尾花) 数据集作为示例。iris 数据集是一个经典的多分类数据集,包含 3 个类别 (setosa, versicolor, virginica) 的鸢尾花,每个类别包含 50 个样本。数据集包含 4 个特征:花萼长度 (sepal length)、花萼宽度 (sepal width)、花瓣长度 (petal length) 和花瓣宽度 (petal width)。
from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler # 1. 加载数据集 iris = load_iris() X = iris.data # 特征数据 y = iris.target # 类别标签 feature_names = iris.feature_names # 特征名称 target_names = iris.target_names # 类别名称 print("特征名称:", feature_names) print("类别名称:", target_names) print("数据形状:", X.shape) # (150, 4) - 150个样本,4个特征 print("类别分布:", set(y)) # {0, 1, 2} - 3个类别 # 2. 划分训练集和测试集 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42, stratify=y) # test_size=0.3: 测试集占总数据的 30% # random_state=42: 设置随机种子,保证结果可重复 # stratify=y: 分层抽样,保证训练集和测试集中各类别比例与原始数据集中一致 print("训练集数据形状:", X_train.shape) # (105, 4) print("测试集数据形状:", X_test.shape) # (45, 4) # 3. 特征缩放 (标准化) scaler = StandardScaler() X_train_scaled = scaler.fit_transform(X_train) # fit_transform 在训练集上拟合和转换 X_test_scaled = scaler.transform(X_test) # transform 在测试集上使用训练集上学习到的参数进行转换 print("标准化后的训练集数据 (前 5 行):\n", X_train_scaled[:5])
代码详解:
load_iris(): 加载 iris 数据集。
iris.data: 获取特征数据 (NumPy 数组)。
iris.target: 获取类别标签 (NumPy 数组)。
iris.feature_names: 获取特征名称列表。
iris.target_names: 获取类别名称列表。
train_test_split(): 将数据集划分为训练集和测试集。
test_size: 设置测试集大小比例。
random_state: 设置随机种子,保证结果可重复。
stratify: 分层抽样,保持类别比例一致。
StandardScaler(): 创建标准化缩放器对象。
scaler.fit_transform(X_train): 在训练集上拟合标准化器并进行转换。
fit(): 计算训练集的均值和标准差。
transform(): 使用计算得到的均值和标准差对数据进行标准化。
scaler.transform(X_test): 使用在训练集上拟合的标准化器对测试集进行转换。注意:测试集只能使用训练集上学习到的参数进行转换,避免信息泄露。
数据预处理的重要性:
3.2.2 模型选择和训练
我们选择逻辑回归 (Logistic Regression) 和支持向量机 (SVM) 两种常用的分类算法进行演示。
3.2.2.1 逻辑回归 (Logistic Regression)
from sklearn.linear_model import LogisticRegression # 1. 创建逻辑回归模型 logreg_model = LogisticRegression(random_state=42, solver='liblinear', multi_class='ovr') # random_state=42: 设置随机种子 # solver='liblinear': 选择求解器,适用于小数据集,对于大数据集可以考虑 'sag' 或 'saga' # multi_class='ovr': 使用 one-vs-rest (OvR) 策略处理多分类问题 # 2. 训练模型 logreg_model.fit(X_train_scaled, y_train) # 使用标准化后的训练集数据和训练集标签进行训练 print("逻辑回归模型训练完成!")
代码详解:
LogisticRegression(): 创建逻辑回归模型对象。
random_state: 设置随机种子。
solver: 选择优化算法求解器。'liblinear' 适用于小数据集,'sag' 和 'saga' 适用于大数据集。
multi_class: 处理多分类问题的策略。'ovr' (one-vs-rest) 将多分类问题分解为多个二分类问题;'multinomial' 直接进行多分类。
logreg_model.fit(X_train_scaled, y_train): 使用训练数据训练逻辑回归模型。
3.2.2.2 支持向量机 (SVM)
from sklearn.svm import SVC # 1. 创建 SVM 模型 svm_model = SVC(random_state=42, kernel='rbf', C=1.0, gamma='scale') # random_state=42: 设置随机种子 # kernel='rbf': 选择核函数,'rbf' (径向基函数) 是常用的非线性核函数,也可用 'linear', 'poly', 'sigmoid' 等 # C=1.0: 正则化参数,控制模型复杂度,C 值越大,模型越复杂,可能过拟合 # gamma='scale': 核函数参数,影响 RBF 核函数的宽度,'scale' 会根据特征维度自动调整 # 2. 训练模型 svm_model.fit(X_train_scaled, y_train) # 使用标准化后的训练集数据和训练集标签进行训练 print("SVM 模型训练完成!")
代码详解:
SVC(): 创建 SVM 分类模型对象 (Support Vector Classifier)。
random_state: 设置随机种子。
kernel: 选择核函数。常用的核函数包括:
'linear': 线性核函数,适用于线性可分数据。
'rbf': 径向基函数 (RBF) 核函数,适用于非线性可分数据,是默认核函数。
'poly': 多项式核函数。
'sigmoid': Sigmoid 核函数。
C: 正则化参数。C 值越大,模型越复杂,容错能力越低,可能过拟合;C 值越小,模型越简单,容错能力越高,可能欠拟合。
gamma: 核函数参数,影响 RBF 核函数的宽度。'scale' (默认值) 会根据特征维度自动调整;'auto' 会根据数据自动调整。也可以手动设置具体数值。
svm_model.fit(X_train_scaled, y_train): 使用训练数据训练 SVM 模型。
模型超参数:
模型超参数是在模型训练之前设置的参数,而不是通过训练数据学习得到的。
不同的模型有不同的超参数,例如逻辑回归的 C 和 solver,SVM 的 kernel、C 和 gamma,决策树的 max_depth 和 min_samples_split 等。
超参数的选择会显著影响模型的性能。通常需要通过交叉验证和网格搜索 (GridSearchCV) 或随机搜索 (RandomizedSearchCV) 等方法进行超参数调优,找到最佳的超参数组合。
3.2.3 模型评估
我们使用测试集数据评估训练好的逻辑回归模型和 SVM 模型的性能,并使用多种评估指标。
from sklearn.metrics import accuracy_score, classification_report, confusion_matrix, roc_auc_score, roc_curve import matplotlib.pyplot as plt import numpy as np # 1. 使用模型进行预测 y_pred_logreg = logreg_model.predict(X_test_scaled) # 逻辑回归模型预测 y_pred_svm = svm_model.predict(X_test_scaled) # SVM 模型预测 y_prob_logreg = logreg_model.predict_proba(X_test_scaled)[:, 1] # 逻辑回归模型预测概率 (用于 AUC-ROC) # predict_proba 返回每个样本属于每个类别的概率,[:, 1] 取出正例 (类别 1) 的概率,假设类别 1 为正例 # 2. 评估逻辑回归模型 print("逻辑回归模型评估:") print("准确率:", accuracy_score(y_test, y_pred_logreg)) print("\n分类报告:\n", classification_report(y_test, y_pred_logreg, target_names=target_names)) print("\n混淆矩阵:\n", confusion_matrix(y_test, y_pred_logreg)) # 3. 评估 SVM 模型 print("\nSVM 模型评估:") print("准确率:", accuracy_score(y_test, y_pred_svm)) print("\n分类报告:\n", classification_report(y_test, y_pred_svm, target_names=target_names)) print("\n混淆矩阵:\n", confusion_matrix(y_test, y_pred_svm)) # 4. 可视化混淆矩阵 (可选) def plot_confusion_matrix(cm, classes, title='Confusion matrix', cmap=plt.cm.Blues): """绘制混淆矩阵""" plt.imshow(cm, interpolation='nearest', cmap=cmap) plt.title(title) plt.colorbar() tick_marks = np.arange(len(classes)) plt.xticks(tick_marks, classes, rotation=45) plt.yticks(tick_marks, classes) thresh = cm.max() / 2. for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])): plt.text(j, i, format(cm[i, j], 'd'), horizontalalignment="center", color="white" if cm[i, j] > thresh else "black") plt.tight_layout() plt.ylabel('True label') plt.xlabel('Predicted label') import itertools plt.figure(figsize=(8, 6)) plot_confusion_matrix(confusion_matrix(y_test, y_pred_logreg), classes=target_names, title='Confusion matrix - Logistic Regression') plt.show() plt.figure(figsize=(8, 6)) plot_confusion_matrix(confusion_matrix(y_test, y_pred_svm), classes=target_names, title='Confusion matrix - SVM') plt.show()
代码详解:
accuracy_score(y_test, y_pred): 计算准确率。
classification_report(y_test, y_pred, target_names=target_names): 生成分类报告,包含精确率、召回率、F1 值和支持度。
confusion_matrix(y_test, y_pred): 生成混淆矩阵。
plot_confusion_matrix(): 自定义函数,用于可视化混淆矩阵 (使用了 matplotlib 库)。
logreg_model.predict(X_test_scaled): 使用逻辑回归模型在测试集上进行预测,返回预测的类别标签。
svm_model.predict(X_test_scaled): 使用 SVM 模型在测试集上进行预测,返回预测的类别标签。
logreg_model.predict_proba(X_test_scaled)[:, 1]: 对于逻辑回归模型,predict_proba 方法返回每个样本属于每个类别的概率。[:, 1] 假设类别 1 为正例,取出所有样本属于类别 1 的概率。注意:predict_proba 方法并非所有分类器都提供,例如 SVM 默认不提供概率预测。
评估指标详解:
准确率: 在 iris 数据集上,逻辑回归和 SVM 模型都取得了较高的准确率,说明模型整体分类效果较好。
分类报告:
精确率 (Precision): 例如,对于 setosa 类别,逻辑回归的精确率为 1.00,表示所有预测为 setosa 的样本中,100% 确实是 setosa。
召回率 (Recall): 例如,对于 setosa 类别,逻辑回归的召回率为 1.00,表示所有真实的 setosa 样本中,100% 被模型预测为 setosa。
F1 值: 精确率和召回率的调和平均值,用于综合评价模型的性能。
支持度 (Support): 每个类别在测试集中实际的样本数量。
混淆矩阵:
混淆矩阵的行表示真实类别,列表示预测类别。
对角线上的数值表示分类正确的样本数量。
非对角线上的数值表示分类错误的样本数量。
通过混淆矩阵可以更详细地了解模型在各个类别上的分类情况,例如模型容易将哪个类别误判为哪个类别。
3.2.4 模型优化 (超参数调优)
我们使用 GridSearchCV (网格搜索交叉验证) 对 SVM 模型的超参数 C 和 gamma 进行调优。
from sklearn.model_selection import GridSearchCV # 1. 设置超参数网格 param_grid = {'C': [0.1, 1, 10, 100], 'gamma': ['scale', 'auto', 0.1, 1]} # C 的候选值: [0.1, 1, 10, 100] # gamma 的候选值: ['scale', 'auto', 0.1, 1] # 2. 创建 GridSearchCV 对象 grid_search = GridSearchCV(SVC(kernel='rbf', random_state=42), # 使用 SVM 模型 param_grid, # 超参数网格 cv=5, # 5 折交叉验证 scoring='accuracy') # 评估指标为准确率 # 3. 运行网格搜索 grid_search.fit(X_train_scaled, y_train) # 在训练集上进行网格搜索和交叉验证 # 4. 获取最佳模型和最佳超参数 best_svm_model = grid_search.best_estimator_ # 最佳模型 best_params = grid_search.best_params_ # 最佳超参数 best_score = grid_search.best_score_ # 最佳交叉验证分数 print("最佳 SVM 模型:", best_svm_model) print("最佳超参数:", best_params) print("最佳交叉验证准确率:", best_score) # 5. 使用最佳模型在测试集上评估 y_pred_best_svm = best_svm_model.predict(X_test_scaled) print("\n最佳 SVM 模型在测试集上的准确率:", accuracy_score(y_test, y_pred_best_svm)) print("\n最佳 SVM 模型分类报告:\n", classification_report(y_test, y_pred_best_svm, target_names=target_names)) print("\n最佳 SVM 模型混淆矩阵:\n", confusion_matrix(y_test, y_pred_best_svm))
代码详解:
GridSearchCV(): 创建 GridSearchCV 对象,用于网格搜索交叉验证。
SVC(kernel='rbf', random_state=42): 指定要进行超参数调优的模型,这里使用 RBF 核函数的 SVM 模型。
param_grid: 超参数网格,字典类型,键为超参数名称,值为超参数候选值列表。
cv=5: 设置 5 折交叉验证。
scoring='accuracy': 设置评估指标为准确率。
grid_search.fit(X_train_scaled, y_train): 在训练集上运行网格搜索和交叉验证。GridSearchCV 会遍历 param_grid 中所有超参数组合,对每种组合进行交叉验证,并记录交叉验证结果。
grid_search.best_estimator_: 获取在交叉验证中表现最佳的模型 (即使用最佳超参数组合训练的模型)。
grid_search.best_params_: 获取最佳超参数组合。
grid_search.best_score_: 获取最佳交叉验证分数 (根据 scoring 参数指定的评估指标)。
交叉验证 (Cross-Validation):
交叉验证是一种评估模型泛化能力的方法,可以更可靠地评估模型在未见过的数据上的表现,避免模型在训练集上过拟合,而在测试集上表现不佳的情况。
K 折交叉验证 (K-Fold Cross-Validation) 将训练集划分为 K 个子集 (fold),每次选择其中 K-1 个子集作为训练集,剩下的 1 个子集作为验证集,进行 K 次训练和验证。最终的评估结果是 K 次验证结果的平均值。
GridSearchCV 中使用交叉验证来评估每种超参数组合的性能,选择交叉验证性能最佳的超参数组合。
网格搜索 (Grid Search):
网格搜索是一种超参数调优方法,它通过遍历预定义的超参数网格中的所有超参数组合,并使用交叉验证评估每种组合的性能,最终选择性能最佳的超参数组合。
网格搜索的缺点是当超参数数量较多或超参数候选值较多时,搜索空间会很大,计算量会显著增加。
其他超参数调优方法:
随机搜索 (RandomizedSearchCV): 与网格搜索不同,随机搜索在超参数空间中随机采样一定数量的超参数组合进行评估。当超参数之间相互独立且对性能的影响程度差异较大时,随机搜索通常比网格搜索更高效。
贝叶斯优化 (Bayesian Optimization): 一种更高级的超参数调优方法,使用贝叶斯模型来建模超参数与性能之间的关系,并根据模型预测选择下一组超参数进行评估,能够更有效地找到最佳超参数组合。
3.2.5 其他分类算法实践 (简要示例)
除了逻辑回归和 SVM,Scikit-learn 还提供了许多其他分类算法。下面我们简要演示如何使用决策树 (Decision Tree) 和随机森林 (Random Forest) 进行分类。
3.2.5.1 决策树 (Decision Tree)
from sklearn.tree import DecisionTreeClassifier # 1. 创建决策树模型 dt_model = DecisionTreeClassifier(random_state=42, max_depth=3) # 限制树的最大深度 # 2. 训练模型 dt_model.fit(X_train, y_train) # 决策树通常不需要特征缩放 # 3. 评估模型 y_pred_dt = dt_model.predict(X_test) print("决策树模型评估:") print("准确率:", accuracy_score(y_test, y_pred_dt)) print("\n分类报告:\n", classification_report(y_test, y_pred_dt, target_names=target_names)) print("\n混淆矩阵:\n", confusion_matrix(y_test, y_pred_dt)) # 4. 可视化决策树 (可选,需要安装 graphviz 和 pydotplus) # from sklearn.tree import export_graphviz # import graphviz # dot_data = export_graphviz(dt_model, out_file=None, # feature_names=feature_names, # class_names=target_names, # filled=True, rounded=True, # special_characters=True) # graph = graphviz.Source(dot_data) # graph.render("iris_decision_tree") # 保存为 PDF 文件