机器学习模型搭建与评估


Datawhale社区 动手学数据分析 第三章 模型搭建和评估 学习记录

  • 模型搭建
    • 数据划分
      • train_test_split()
    • 模型选择和拟合数据
      • 模型实例化、 fit()
    • 预测
      • predict()
      • predict_proba()
  • 模型评估
    • 交叉验证
      • cross_val_score()
      • cross_val_predict()
    • 混淆矩阵
      • cofusion_matrix()
      • classification_report() , precision_score() , recall_score() , f1_score()
      • precision_recall_curve()
    • ROC曲线
      • roc_curve()
      • roc_auc_score()

第三章 模型搭建和评估–建模

我们拥有的泰坦尼克号的数据集,那么我们这次的目的就是,完成泰坦尼克号存活预测这个任务。

import pandas as pd
import numpy as np
%matplotlib inline

载入我们提供清洗之后的数据(clear_data.csv),大家也将原始数据载入(train.csv),说说他们有什么不同

#写入代码
orgin_data = pd.read_csv('train.csv')
orgin_data.head(3)
PassengerId Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
0 1 0 3 Braund, Mr. Owen Harris male 22.0 1 0 A/5 21171 7.2500 NaN S
1 2 1 1 Cumings, Mrs. John Bradley (Florence Briggs Th... female 38.0 1 0 PC 17599 71.2833 C85 C
2 3 1 3 Heikkinen, Miss. Laina female 26.0 0 0 STON/O2. 3101282 7.9250 NaN S
#写入代码
clean_data = pd.read_csv('clear_data.csv')
clean_data.head(3)
PassengerId Pclass Age SibSp Parch Fare Sex_female Sex_male Embarked_C Embarked_Q Embarked_S
0 0 3 22.0 1 0 7.2500 0 1 0 0 1
1 1 1 38.0 1 0 71.2833 1 0 1 0 0
2 2 3 26.0 0 0 7.9250 1 0 0 0 1

#不同

  1. 删除了 Survived 特征(将标签独立出来)
  2. 将文本特征 Sex, Embarked 转换为了 One-hot 编码
  3. 删除了原数据中的 Name, Ticket, Cabin 特征

模型搭建

  • 处理完前面的数据我们就得到建模数据,下一步是选择合适模型
  • 在进行模型选择之前我们需要先知道数据集最终是进行监督学习还是无监督学习
  • 模型的选择一方面是通过我们的任务来决定的。
  • 除了根据我们任务来选择模型外,还可以根据数据样本量以及特征的稀疏性来决定
  • 刚开始我们总是先尝试使用一个基本的模型来作为其baseline,进而再训练其他模型做对比,最终选择泛化能力或性能比较好的模型

【思考】数据集哪些差异会导致模型在拟合数据是发生变化

#思考回答
样本数量、特征数量、特征重要性、样本分布差距、噪声等

任务一:切割训练集和测试集

这里使用留出法划分数据集

  • 将数据集分为自变量和因变量
  • 按比例切割训练集和测试集(一般测试集的比例有30%、25%、20%、15%和10%)
  • 使用分层抽样
  • 设置随机种子以便结果能复现

【思考】

  • 划分数据集的方法有哪些?
  • 为什么使用分层抽样,这样的好处有什么?

#思考

  1. 划分数据集的方法
  • 留出法
    • 随机划分
    • 分层抽样
  • K 折交叉验证
  • 自助法
  1. 分层抽样可以使划分后数据保存原始数据的分布

任务提示1

  • 切割数据集是为了后续能评估模型泛化能力
  • sklearn中切割数据集的方法为train_test_split
  • 查看函数文档可以在jupyter noteboo里面使用train_test_split?后回车即可看到
  • 分层和随机种子在参数里寻找

要从clear_data.csv和train.csv中提取train_test_split()所需的参数

#写入代码
X = clean_data
y = orgin_data.Survived
#写入代码
from sklearn.model_selection import train_test_split
#写入代码
?train_test_split
#写入代码
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42, stratify=y)
X_train.shape, X_test.shape, y_train.shape, y_test.shape
((712, 11), (179, 11), (712,), (179,))

【思考】

  • 什么情况下切割数据集的时候不用进行随机选取
#思考回答

1. 数据集非常大,随机划分即可能浪费大量时间,也可能降低准确率
2. 时序数据,采用分段切割,避免数据泄露
3. 数据类别不平衡,会采用重采样

任务二:模型创建

  • 创建基于线性模型的分类模型(逻辑回归)
  • 创建基于树的分类模型(决策树、随机森林)
  • 分别使用这些模型进行训练,分别的到训练集和测试集的得分
  • 查看模型的参数,并更改参数值,观察模型变化

提示

  • 逻辑回归不是回归模型而是分类模型,不要与LinearRegression混淆
  • 随机森林其实是决策树集成为了降低决策树过拟合的情况
  • 线性模型所在的模块为sklearn.linear_model
  • 树模型所在的模块为sklearn.ensemble
#写入代码
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
#写入代码
lr = LogisticRegression(max_iter=3000)
lr.fit(X_train, y_train)
lr.get_params()
{'C': 1.0,
 'class_weight': None,
 'dual': False,
 'fit_intercept': True,
 'intercept_scaling': 1,
 'l1_ratio': None,
 'max_iter': 3000,
 'multi_class': 'auto',
 'n_jobs': None,
 'penalty': 'l2',
 'random_state': None,
 'solver': 'lbfgs',
 'tol': 0.0001,
 'verbose': 0,
 'warm_start': False}
#写入代码 查看训练集和测试集的得分
print("Training set score: {:.2f} ,Testing set score: {:.2f}".format(lr.score(X_train, y_train), lr.score(X_test, y_test)))
Training set score: 0.81 ,Testing set score: 0.80
#写入代码
rfc = RandomForestClassifier()
rfc.fit(X_train, y_train)
rfc.get_params()
{'bootstrap': True,
 'ccp_alpha': 0.0,
 'class_weight': None,
 'criterion': 'gini',
 'max_depth': None,
 'max_features': 'auto',
 'max_leaf_nodes': None,
 'max_samples': None,
 'min_impurity_decrease': 0.0,
 'min_impurity_split': None,
 'min_samples_leaf': 1,
 'min_samples_split': 2,
 'min_weight_fraction_leaf': 0.0,
 'n_estimators': 100,
 'n_jobs': None,
 'oob_score': False,
 'random_state': None,
 'verbose': 0,
 'warm_start': False}
#写入代码 查看训练集和测试集的得分
print("Training set score: {:.2f} ,Testing set score: {:.2f}".format(rfc.score(X_train, y_train), rfc.score(X_test, y_test)))
Training set score: 1.00 ,Testing set score: 0.82

【思考】

  • 为什么线性模型可以进行分类任务,背后是怎么的数学关系
  • 对于多分类问题,线性模型是怎么进行分类的

#思考回答

  • 利用输入的特征计算一个加权和 s = w T x s=w^Tx s=wTx,再通过激活函数映射到0和1之间进行分类
  • 可以转换为多个二分类问题

任务三:输出模型预测结果

  • 输出模型预测分类标签
  • 输出不同分类标签的预测概率

提示3

  • 一般监督模型在sklearn里面有个predict能输出预测标签,predict_proba则可以输出标签概率
#写入代码
pred = lr.predict(X_test)
pred[:5]
array([0, 0, 0, 0, 1], dtype=int64)
#写入代码
pred_proba = lr.predict_proba(X_test)
pred_proba[:5]
array([[0.92961653, 0.07038347],
       [0.95523041, 0.04476959],
       [0.8395754 , 0.1604246 ],
       [0.96137521, 0.03862479],
       [0.34067921, 0.65932079]])

【思考】

  • 预测标签的概率对我们有什么帮助
#思考回答  
获取模型对预测结果的确信程度

第三章 模型搭建和评估-评估

根据之前的模型的建模,我们知道如何运用sklearn这个库来完成建模,以及我们知道了的数据集的划分等等操作。那么一个模型我们怎么知道它好不好用呢?以至于我们能不能放心的使用模型给我的结果呢?那么今天的学习的评估,就会很有帮助。

加载下面的库

import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
from IPython.display import Image
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
%matplotlib inline
plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号
plt.rcParams['figure.figsize'] = (10, 6)  # 设置输出图片大小

任务:加载数据并分割测试集和训练集

#写入代码
data = pd.read_csv('clear_data.csv')
train = pd.read_csv('train.csv')
X = data
y = train['Survived']
from sklearn.model_selection import train_test_split
#写入代码
X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y, random_state=0)
#写入代码
lr = LogisticRegression(max_iter=1000)
lr.fit(X_train, y_train)
LogisticRegression(max_iter=1000)

模型评估

模型评估是为了知道模型的泛化能力。

  • K 折交叉验证(k-fold cross-validation)
  • 混淆矩阵(confusion_matrix)
    • 准确率(precision)
    • 召回率(recall)
    • F1 分数
  • ROC曲线

任务一:交叉验证

  • 用10折交叉验证来评估之前的逻辑回归模型
  • 计算交叉验证精度的平均值
#提示:交叉验证
Image('Snipaste_2020-01-05_16-37-56.png')

在这里插入图片描述

提示4

  • 交叉验证在sklearn中的模块为sklearn.model_selection
#载入模块
from sklearn.model_selection import cross_val_score
#K折交叉验证
lr = LogisticRegression(C=100, max_iter=1000)
scores = cross_val_score(lr, X_train, y_train, cv=10)
scores
array([0.8358209 , 0.7761194 , 0.82089552, 0.80597015, 0.85074627,
       0.86567164, 0.73134328, 0.85074627, 0.75757576, 0.6969697 ])
#获取K折平均值
print("Average cross-validation score: {:.2f}".format(scores.mean()))
Average cross-validation score: 0.80

思考4

  • k折越多的情况下会带来什么样的影响?
#思考回答  
增加了计算开销

任务二:混淆矩阵

  • 计算二分类问题的混淆矩阵
  • 计算精确率、召回率以及f-分数

【思考】什么是二分类问题的混淆矩阵,理解这个概念,知道它主要是运算到什么任务中的

#思考回答  
混淆矩阵用于评估分类器性能,其总体思路就是统计A类别实例被分成为B类别的次数  
混淆矩阵中的行表示实际类别,列表示预测类别  
#提示:混淆矩阵
Image('Snipaste_2020-01-05_16-38-26.png')


在这里插入图片描述

#提示:准确率 (Accuracy),精确度(Precision),Recall,f-分数计算方法
Image('Snipaste_2020-01-05_16-39-27.png')


在这里插入图片描述

提示5

  • 混淆矩阵的方法在sklearn中的sklearn.metrics模块
  • 混淆矩阵需要输入真实标签和预测标签
  • 精确率、召回率以及f-分数可使用classification_report模块
#写入代码
from sklearn.metrics import confusion_matrix
#写入代码
lr = LogisticRegression(C=100, max_iter=500)
lr.fit(X_train, y_train)
LogisticRegression(C=100, max_iter=500)
#写入代码
pred = lr.predict(X_train)
#写入代码
confusion_matrix(y_train, pred)
array([[350,  62],
       [ 71, 185]], dtype=int64)
from sklearn.metrics import classification_report
print(classification_report(y_train, pred))
              precision    recall  f1-score   support

           0       0.83      0.85      0.84       412
           1       0.75      0.72      0.74       256

    accuracy                           0.80       668
   macro avg       0.79      0.79      0.79       668
weighted avg       0.80      0.80      0.80       668

【思考】

  • 如果自己实现混淆矩阵的时候该注意什么问题
#思考回答  
混淆矩阵中每个值代表的含义和位置,即 TN,FP,FN,TP。  

绘制 PR 曲线

from sklearn.metrics import precision_recall_curve

precisions, recalls, thresholds = precision_recall_curve(y_test, lr.decision_function(X_test))
plt.plot(precisions, recalls)
plt.xlabel("precision")
plt.ylabel("recall")
plt.grid();

在这里插入图片描述

def plot_precision_recall_vs_threshold(precisions, recalls, thresholds):
    plt.plot(thresholds, precisions[:-1], "b--", label="Precision")
    plt.plot(thresholds, recalls[:-1], "g-", label="Recall")
    plt.legend(loc=0)
    plt.xlabel("thresholds")
    plt.grid()

plot_precision_recall_vs_threshold(precisions, recalls, thresholds);

在这里插入图片描述

任务三:ROC曲线

  • 绘制ROC曲线

【思考】什么是ROC曲线,ROC曲线的存在是为了解决什么问题?

#《机器学习实战》  
**受试者工作特征曲线(简称ROC)**
绘制是真正类率(召回率,灵敏度)和假正类率(FPR)关系。  
FPR是被错误分为正类的负类实例比率。它等于1减去真负类率(TNR),后者是被正确分类为负类的负类实例比率,也称为特异度。  


**ROC曲线和PR曲线的选取:**  
一个经验法则是,当正类非常少见或者你更关注假正类而不是假负类时,应该选择PR曲线,反之则是ROC曲线。

提示6

  • ROC曲线在sklearn中的模块为sklearn.metrics
  • ROC曲线下面所包围的面积越大越好
#写入代码
from sklearn.metrics import roc_curve
#写入代码
fpr, tpr, thresholds = roc_curve(y_test, lr.decision_function(X_test))
plt.plot(fpr, tpr, label="ROC Curve")
plt.xlabel("FPR")
plt.ylabel("TPR (recall)")
plt.grid();


在这里插入图片描述

思考6

  • 对于多分类问题如何绘制ROC曲线
#思考回答
绘制每个类别的ROC曲线

【思考】你能从这条ROC曲线的到什么信息?这些信息可以做什么?

#思考回答  
ROC曲线下面积,用来指导模型选择。

【注】
仅个人学习记录,详细内容见Datawhale社区开源课程 动手学数据分析

猜你喜欢

转载自blog.csdn.net/qq_38869560/article/details/128758063