Task05:模型搭建和评估

4模型搭建和评估

4.1 模型建立和评估–建模

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

【思考】这些库的作用是什么呢?

思考题回答
matplotlib.pyplot作为绘制图形的工具
Seaborn为matplotlib提供了多种绘制图形的美化功能
seaborn.set_style(style=None)#设定绘制图形的主题风格,修改轴的颜色
seaborn.despine()#从图中移除顶部和右侧边框
seaborn.relplot(x=’’,y=’’,data=xxx):绘制散点图
seaborn.catplot(x=’’,y=’’,data=xxx):绘制离散图
seaborn.boxplot(x=’’,y=’’,data=xxx):绘制箱线图
ipython是一个python的交互式shell,比默认的python shell好用得多,支持变量自动补全,自动缩进,支持bash shell命令,内置了许多很有用的功能和函数

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

df1=pd.read_csv('clear_data.csv')
df1.head()
PassengerIdPclassAgeSibSpParchFareSex_femaleSex_maleEmbarked_CEmbarked_QEmbarked_S
00322.0107.250001001
11138.01071.283310100
22326.0007.925010001
33135.01053.100010001
44335.0008.050001001
df2=pd.read_csv('train.csv')
df2.head()
PassengerIdSurvivedPclassNameSexAgeSibSpParchTicketFareCabinEmbarked
0103Braund, Mr. Owen Harrismale22.010A/5 211717.2500NaNS
1211Cumings, Mrs. John Bradley (Florence Briggs Th...female38.010PC 1759971.2833C85C
2313Heikkinen, Miss. Lainafemale26.000STON/O2. 31012827.9250NaNS
3411Futrelle, Mrs. Jacques Heath (Lily May Peel)female35.01011380353.1000C123S
4503Allen, Mr. William Henrymale35.0003734508.0500NaNS

清洗后的数据把用户名、船票信息、客舱这些干扰信息删除了,并把男女性拆分开,登船港口也拆分开,方便后续对不同登船港口人数统计。

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

思考回答
1.数据样本的数量
2.是否还存在干扰或无效特征

4.1.1 切割训练集和测试集

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

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

【提示】

  • 切割数据集是为了后续能评估模型泛化能力
  • sklearn中切割数据集的方法为train_test_split
  • 查看函数文档可以在jupyter noteboo里面使用train_test_split?后回车即可看到
  • 分层和随机种子在参数里寻找
  • 要从clear_data.csv和train.csv中提取train_test_split()所需的参数
from sklearn.model_selection import train_test_split

一般先取出X和y后再切割,有些情况会使用到未切割的,这时候X和y就可以用,x是清洗好的数据,y是我们要预测的存活数据’Survived’

X=df1
y=df2.Survived
y
0      0
1      1
2      1
3      1
4      0
      ..
886    0
887    1
888    0
889    1
890    0
Name: Survived, Length: 891, dtype: int64

参数stratify:依据标签y,按原数据y中各类比例,分配给train和test,使得train和test中各类数据的比例与原数据集一样

X_train,X_test,y_train,y_test=train_test_split(X,y,stratify=y,random_state=0)
#查看拆分的数量
X_train.shape, X_test.shape
((668, 11), (223, 11))

【思考】什么情况下切割数据集的时候不用进行随机选取?

思考回答
数据集过大或过小的时候,数据集数据间没有任何关联的时候(只带随机)。

4.1.2 模型创建

查看所需模型的参数

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

【提示】

  • 逻辑回归不是回归模型而是分类模型,不要与LinearRegression混淆
  • 随机森林其实是决策树集成为了降低决策树过拟合的情况
  • 线性模型所在的模块为sklearn.linear_model
  • 树模型所在的模块为sklearn.ensemble
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
#创建线性模型
lr = LogisticRegression().fit(X_train, y_train)
print("训练集得分: {:.4f}".format(lr.score(X_train, y_train)))
print("测试集得分: {:.4f}".format(lr.score(X_test, y_test)))
训练集得分: 0.8024
测试集得分: 0.7937
'''
正则化可以限制线性模型的复杂度,从而减少模型的过拟合的可能。
添加正则化系数的倒数(默认c=1)
'''
lr1 = LogisticRegression(C=100).fit(X_train, y_train)
print("训练集得分: {:.4f}".format(lr1.score(X_train, y_train)))
print("测试集得分: {:.4f}".format(lr1.score(X_test, y_test)))
训练集得分: 0.7904
测试集得分: 0.7758
#创建随机森林模型
rfc = RandomForestClassifier().fit(X_train, y_train)
print("训练集得分: {:.4f}".format(rfc.score(X_train, y_train)))
print("测试集得分: {:.4f}".format(rfc.score(X_test, y_test)))
训练集得分: 1.0000
测试集得分: 0.8161
'''
n_estimators:森林中树的数量(默认100),max_depth:树的最大深度(深度越大,可以分得更细) ,min_samples_leaf:在叶节点处需要的最小样本数,可能对模型具有平滑作用
'''
rfc1 = RandomForestClassifier(n_estimators=50, max_depth=3,min_samples_leaf=16).fit(X_train, y_train)
print("训练集得分: {:.4f}".format(rfc1.score(X_train, y_train)))
print("测试集得分: {:.4f}".format(rfc1.score(X_test, y_test)))
训练集得分: 0.8263
测试集得分: 0.7668

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

思考回答
引用西瓜书的内容:通过特征x(x1,x2… ,xd)求取出y,二分类利用y的正反从而进行分类,多分类的基本思路是"拆解法"即将多分类任务拆为若干个二分类任务求解.具体来说,先对问题进行拆分,然后为拆出的每个二分类任务训练一个分类器;在测试时,对这些分类器的预测结果进行集成以获得最终的多分类结果。最经典的拆分策略有三种: “一对一” (One vs One ,简称 OvO) “一对其余” (One vs Rest ,简称 OvR) 和"多对多" (Many vs Many,简称 MvM)。
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

4.1.3 输出模型预测结果

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

【提示】

  • 一般监督模型在sklearn里面有个predict能输出预测标签,predict_proba则可以输出标签概率
#预测X中样本的类别标签
lr.predict(X_test)
array([0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1,
       0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
       0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1,
       1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0,
       0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0,
       0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0,
       0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0,
       0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0,
       0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0,
       0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0,
       0, 0, 0], dtype=int64)
#返回按类别标签排序的所有类别的估计值
lr.predict_proba(X_test)
array([[0.85605638, 0.14394362],
       [0.85707365, 0.14292635],
       [0.94974343, 0.05025657],
       [0.92520205, 0.07479795],
       [0.68853429, 0.31146571],
       [0.45640977, 0.54359023],
             ·············
       [0.25621312, 0.74378688],
       [0.74682248, 0.25317752],
       [0.91233219, 0.08766781],
       [0.86855855, 0.13144145],
       [0.6079257 , 0.3920743 ]])
zx=X_test
zx.head()
PassengerIdPclassAgeSibSpParchFareSex_femaleSex_maleEmbarked_CEmbarked_QEmbarked_S
288288242.00013.000001001
86986934.01111.133301001
18218239.04231.387501001
684684260.01139.000001001
599599149.01056.929201100

【思考】预测标签的概率对我们有什么帮助?

思考回答
predict_proba输出结果解析:上面predict_proba对id288的乘客预测的死亡概率为0.85605638,存活概率为0.14394362,id299的乘客预测的死亡概率为0.85707365,存活概率为0.14292635,以此类推。可以通过预测标签的概率大概知道模型有对某一个乘客生存情况的预测准确性,例如id288的乘客85%的概率死亡,14%存活,如果真实数据是该乘客是死亡,那准确率就有意义,如果模型输出结果id288的乘客有85%的概率死亡,14%的概率存活,这时候预测的结果应该为死亡,但真正的数据是该乘客是存活的,那么通过这些概率可以说明模型还存在问题。

4.2 模型搭建和评估-评估

#先导包
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
from IPython.display import Image
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
%matplotlib inline
#加载数据并分割测试集和训练集
df=pd.read_csv('clear_data.csv')
df1=pd.read_csv('train.csv')
X=df
y=df1.Survived
X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y, random_state=0)
lr=LogisticRegression().fit(X_train,y_train)
  • 模型评估是为了知道模型的泛化能力。
  • 交叉验证(cross-validation)是一种评估泛化性能的统计学方法,它比单次划分训练集和测试集的方法更加稳定、全面。
  • 在交叉验证中,数据被多次划分,并且需要训练多个模型。
  • 最常用的交叉验证是 k 折交叉验证(k-fold cross-validation),其中 k 是由用户指定的数字,通常取 5 或 10。
  • 准确率(precision)度量的是被预测为正例的样本中有多少是真正的正例
  • 召回率(recall)度量的是正类样本中有多少被预测为正类
  • f-分数是准确率与召回率的调和平均

【思考】:将上面的概念进一步的理解,大家可以做一下总结

思考回答
首先将全部样本划分成K个大小相等的样本子集,依次遍历这k个子集,每次把当前子集作为验证集,其余的子集作为训练集。最后把K次评估指标的平均值作为最终的评估指标,在实际实验中,K经常取10。通过准确率和召回率判断出模型的好坏。

4.2.1 交叉验证

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

请添加图片描述

【提示】

  • 交叉验证在sklearn中的模块为sklearn.model_selection
from sklearn.model_selection import cross_val_score
#cv:确定交叉验证切分策略(默认使用5折交叉验证)
lr1=LogisticRegression()
score=cross_val_score(lr1,X_train,y_train,cv=15)
score
array([0.86666667, 0.73333333, 0.75555556, 0.84444444, 0.8       ,
       0.77777778, 0.82222222, 0.8       , 0.93181818, 0.77272727,
       0.77272727, 0.84090909, 0.77272727, 0.72727273, 0.72727273])
print("平均交叉验证得分: {:.3f}".format(score.mean()))
平均交叉验证得分: 0.796

【思考】 k折越多的情况下会带来什么样的影响?

思考回答
k折越多,模型的得分并不会明显增加,只能起到平滑作用甚至出现(模型变坏)得分下降的情况,同时k 值过大,会降低运算速度。

4.2.2 混淆矩阵

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

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

思考回答
主要运算到我们需要知道所分类占总数的比率

#提示:混淆矩阵
Image('Snipaste_2020-01-05_16-38-26.png')

在这里插入图片描述

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

在这里插入图片描述

【提示】

  • 混淆矩阵的方法在sklearn中的sklearn.metrics模块
  • 混淆矩阵需要输入真实标签和预测标签
  • 精确率、召回率以及f-分数可使用classification_report模块
from sklearn.metrics import confusion_matrix
pred=lr.predict(X_train)
#混淆矩阵需要输入真实标签和预测标签
confusion_matrix(y_train,pred)
array([[358,  54],
       [ 78, 178]], dtype=int64)
from sklearn.metrics import classification_report
#求准确率、召回率和f1
print(classification_report(y_train, pred))
              precision    recall  f1-score   support

           0       0.82      0.87      0.84       412
           1       0.77      0.70      0.73       256

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

4.2.3 ROC曲线

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

思考回答
根据学习器的预测结果对样例进行排序,按此顺序逐个把样本作为正例进行预测,每次计算出两个重要量的值,分别以它们为横、纵坐标作图’就得到了 ROC 曲线。AUC是一种用来度量分类模型好坏的一个标准,面积越大模型越好。

【提示6】

  • ROC曲线在sklearn中的模块为sklearn.metrics
  • ROC曲线下面所包围的面积越大越好
from sklearn.metrics import roc_curve

decision_function参数:
在这里插入图片描述

'''
sklearn.metrics.roc_curve(y_true, y_score)
decision_function大致可以理解为跟predict_proba一样返回类别的估计值,只是decision_function所返回的估计值是带正负号的
'''
fpr, tpr, thresholds = roc_curve(y_test, lr.decision_function(X_test))
plt.plot(fpr, tpr, label="ROC曲线")
plt.xlabel("FPR(假正例率)")
plt.ylabel("TPR (真正例率)")
#abs为绝对值,argmin取得接近0的下标
close_zero = np.argmin(np.abs(thresholds))
#fillstyle填充圆点,
plt.plot(fpr[close_zero], tpr[close_zero], 'o', markersize=10, label="threshold zero", fillstyle="none")
plt.legend(loc=4)

请添加图片描述

【思考】对于多分类问题如何绘制ROC曲线?

思考回答
方法一:每种类别下,都可以得到m个测试样本为该类别的概率(矩阵P中的列)。所以,根据概率矩阵P和标签矩阵L中对应的每一列,可以计算出各个阈值下的假正例率(FPR)和真正例率(TPR),从而绘制出一条ROC曲线。这样总共可以绘制出n条ROC曲线。最后对n条ROC曲线取平均,即可得到最终的ROC曲线。
方法二:
对于一个测试样本:
(1)标签只由0和1组成,1的位置表明了它的类别(可对应二分类问题中的“正”),0就表示其他类别(“负”);
(2)要是分类器对该测试样本分类正确,则该样本标签中1对应的位置在概率矩阵P中的值是大于0对应的位置的概率值的。基于这两点,将标签矩阵L和概率矩阵P分别按行展开,转置后形成两列,这就得到了一个二分类的结果。所以,此方法经过计算后可以直接得到最终的ROC曲线。

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

在这里插入图片描述

思考回答
根据roc下面所包含的面积来确认自己的模型好坏,从而对模型进行改进。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值