Datawhale数据分析课程第三章建模与评估


经过前面的两章的知识点的学习,可以对数据的本身进行处理,比如数据本身的增删查补,还可以做必要的清洗工作。那么下面我们就要开始使用我们前面处理好的数据了。这一章我们要做的就是使用数据,我们做数据分析的目的也就是,运用我们的数据以及结合我的业务来得到某些我们需要知道的结果。那么分析的第一步就是建模,搭建一个预测模型或者其他模型;我们从这个模型的到结果之后,我们要分析我的模型是不是足够的可靠,那我就需要评估这个模型。

建模

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

导入各种库及可视化设置

import pandas as pd#用于数据处理的库,围绕DataFrame数据类型为核心开展
import numpy as np#科学计算的基础包,快速高效的多维数组对象ndarray,用于对数组执行元素及计算或直接对数组执行数学运算,线性代数运算、傅里叶变换、随机数生成、集成c、c++等代码到python
import matplotlib.pyplot as plt#数据可视化库
import seaborn as sns#基于matplotlib的数据可视化库
from IPython.display import Image#基于Matplotlib库的数据可视化库
%matplotlib inline#%matplotlib inline 可以在Ipython编译器里直接使用,功能是可以内嵌绘图,并且可以省略掉plt.show()这一步。
plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号
plt.rcParams['figure.figsize'] = (10, 6)  # 设置输出图片大小

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

data=pd.read_csv("clear_data.csv")
train=pd.read_csv("train.csv")
  • 从列名上看,清洗过的数据删除了Name、Ticket、Cabin等与建模无关的列数据
  • 将Sex列和Embarked列进行独热编码
  • 对原数据中的空缺值进行了填充
  • 处理后的数据仅有int和flaot两种数据类型

模型的选择路径

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

在这里插入图片描述

模型搭建

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

  • 训练集、测试集的样本划分是否均衡,是否存在某类样本集中在某个数据集上的情况
  • 数据是否具有代表性
  • 数据之间是否存在联系,比如时间上的先后顺序
  • 机器学习的一个重要假设是数据独立同分布
  • 数据量是否足够

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

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

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

问题:

  1. 为什么要划分数据集
    • 用于检验模型的拟合程度、泛化能力及稳定性
    • 一般而言,训练集表现好但测试集表现不好的模型存在过拟合风险,训练集的效果明显差于测试集则模型有欠拟合风险
    • 过拟合:模型学习的过于细致
    • 欠拟合:模型学习的过于粗糙
  2. 划分数据集的方法有哪些?
    • 留出法
      • “留出法”直接将数据集D划分为两个互斥的集合,一个为训练集S,一个为测试集T,即D=S∪T,S∩T=∅.在S上进行模型学习,然后用T来评估其测试误差,作为对泛化误差的估计。
      • 单次使用留出法得到的估计结果往往不够稳定可靠,在使用留出法时,一般要采用若干次随机划分、重复进行模型评估后取平均值作为留出法的评估结果。
      • 数据量为10000左右。如果只是划成训练集和测试集则为:70%验证集,30%测试集。如果划成训练集、验证集和测试集则为:60%训练集,20%验证集,20%测试集。
      • 数据量为百万级别。 验证集和测试集占数据总量的比例会趋向变得更小。比如有1000000条数据,只需各拿出10000条作为验证集和测试集。
    • 交叉验证法
      • 首先将数据分成两部分,左边训练集,右边测试集,训练集用于建立模型,在建模过程中不能加入任何与测试集有关的信息,否则相当于泄题。
      • 再将训练集切分成多份,假设分为了10份,在验证某一次结果是,需要把整个过程分成10步,第一步用前九份作训练集,最后一份做验证集,得到一个结果,以此类推,每一次都用另外一份作为验证集,其他作为训练集。经过10步以后,训练集的每一份都作了一次验证集,得到10个结果。
      • 对最终的10个结果进行平均。
      • “交叉验证法”先将数据集D划分为k个大小相同的互斥子集,即D=D1∪D2∪⋯∪Dk,Di∩Dj=∅(i≠j).其中每个子集Di都应尽量保持数据分布的一致性,即从D中通过分层采样得到。
      • 然后,每次都用其中的k−1个子集的并集作为训练集,余下一个作为测试集,这样就可以得到k组训练集/测试集,从而可以进行k次模型的学习,并把这k个测试结果的均值作为评估结果,通常我们把交叉验证法称为“k折交叉验证”。
      • 优点:从有限的数据中尽可能挖掘多的信息,从各种角度去学习我们现有的有限的数据,避免出现局部的极值。在这个过程中无论是训练样本还是测试样本都得到了尽可能多的学习。
        ​ - 缺点:当数据集比较大时,训练模型的开销较大。
    • 自助法
      • 每次随机从初始数据集 D 中选择一个样本拷贝到结果数据集 D′ 中,重复操作 m 次 ,就得到了含有 m 个样本的数据集 D′ (注意:D 中有部分样本会在 D′ 中多次出现)。将 D′ 作为训练集,D∖D′ 作为验证集(测试集)。样本在 m 次采样中始终不被采集到的概率是 ( 1 − 1 m ) m (1-\cfrac{1}{m})^m (1m1)m,取极限为: lim ⁡ m ⟶ ∞ ( 1 − 1 m ) m = 1 e ≈ 0.368 \mathop{\lim}\limits_{m\longrightarrow\infty}(1-\cfrac{1}{m})^m=\cfrac{1}{e}\approx0.368 mlim(1m1)m=e10.368,通过自助采样,初始数据集中约有36.8%的样本未出现在采样集 D′ 中。
      • 优点:自助法在数据集较小、难以有效划分训练集和测试集时很有用。此外,自助法能从初始数据集中产生多个不同的训练集,这对集成学习等方法有很大的好处。
      • 缺点:自助法产生的数据集改变了初始数据集的分布,这会引入估计偏差。因此在初始数据量足够时,留出法和交叉验证法更加常用一些。
  3. 为什么使用分层抽样,这样的好处有什么?
    • 可以保证抽样后各数据集的样本比例相同,从而避免因样本分布差异而导致的偏差。
    • 使用分层抽样后,如果模型在不同数据集上效果差异大,我们可以更有把把握是因为拟合问题,而非数据问题。
from sklearn.model_selection import train_test_split
#使用sklearn.model_selection中的train_test_split进行分层抽样
#通过stratify参数指定分层对应的变量,如果不指定stratify参数则为普通的随机抽样
train_test_split?#查看函数参数,截取在下
'''
* arrays:具有相同长度/形状的可索引序列[0]
    允许的输入是列表,numpy数组,scipy-sparse
    矩阵或pandas dataframes。
test_size:float,int或None,可选(默认=None)
    如果为float,则应介于0.0到1.0之间并代表比例
    包含在测试拆分中的数据集的数量。如果为int,则表示
    测试样品的绝对数量。如果为None,则将值设置为
    训练集补集的大小。如果``train_size``也为None,它将
    设置为0.25。
train_size:浮点数,整数或无,(默认=无)
    如果为float,则应介于0.0和1.0之间,并表示
    数据集要包含在火车分割中的比例。如果
    int,表示火车样本的绝对数量。如果没有,
    该值将自动设置为测试大小的补码。
random_state:int,RandomState实例或无,可选(默认值:无)
    如果为int,则random_state是随机数生成器使用的种子;否则为false。
    如果是RandomState实例,则random_state是随机数生成器;
    如果为None,则随机数生成器是使用的RandomState实例
    通过`np.random`。
shuffle:布尔值,可选(默认= True)
    拆分前是否对数据进行混洗。如果shuffle = False
    然后分层必须为“无”。
分层:类数组或无(默认=无)
    如果不是None,则以分层方式拆分数据,使用
    类标签。
    '''
X = data#DataFrame
y = train['Survived']#Series
#对数据集按照y进行分层抽样,随机种子为0,为保证每次运行结果一样
#返回结果中X_train、X_test为DataFrame类型,y_train、 y_test为Series类型
X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y, random_state=0)

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

任务二:模型创建

创建基于线性模型的分类模型(逻辑回归)
lr = LogisticRegression()#会出现警告lbfgs 无法收敛,要求增加迭代次数
lr.fit(X_train, y_train)
#调整迭代次数重新创建模型,警告消除
lr = LogisticRegression(max_iter=1000)
lr.fit(X_train, y_train)
'''
LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,
                   intercept_scaling=1, l1_ratio=None, max_iter=1000,
                   multi_class='auto', n_jobs=None, penalty='l2',
                   random_state=None, solver='lbfgs', tol=0.0001, verbose=0,
                   warm_start=False)
'''
# 查看训练集和测试集score值
print("Training set score: {:.2f}".format(lr.score(X_train, y_train)))
print("Testing set score: {:.2f}".format(lr.score(X_test, y_test)))
#Training set score: 0.81
#Testing set score: 0.78
# 调整参数后的逻辑回归模型
lr2 = LogisticRegression(C=100,max_iter=1000)
lr2.fit(X_train, y_train)
'''
LogisticRegression(C=100, class_weight=None, dual=False, fit_intercept=True,
                   intercept_scaling=1, l1_ratio=None, max_iter=1000,
                   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}".format(lr2.score(X_train, y_train)))
print("Testing set score: {:.2f}".format(lr2.score(X_test, y_test)))
#Training set score: 0.80
#Testing set score: 0.78

创建基于树的分类模型(决策树、随机森林)
# 默认参数的随机森林分类模型
rfc = RandomForestClassifier()
rfc.fit(X_train, y_train)
'''
RandomForestClassifier(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}".format(rfc.score(X_train, y_train)))
print("Testing set score: {:.2f}".format(rfc.score(X_test, y_test)))
#Training set score: 1.00
#Testing set score: 0.83
# 调整参数后的随机森林分类模型
rfc2 = RandomForestClassifier(n_estimators=100, max_depth=5)
rfc2.fit(X_train, y_train)
'''
RandomForestClassifier(bootstrap=True, ccp_alpha=0.0, class_weight=None,
                       criterion='gini', max_depth=5, 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}".format(rfc2.score(X_train, y_train)))
print("Testing set score: {:.2f}".format(rfc2.score(X_test, y_test)))
#Training set score: 0.87
#Testing set score: 0.81

为什么线性模型可以进行分类任务,背后是怎么的数学关系?
基于逻辑回归的分类预测模型
对于多分类问题,线性模型是怎么进行分类的?
在这里插入图片描述

在这里插入图片描述

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

#输出逻辑回归的预测结果
pred = lr.predict(X_train)
pred
'''
array([0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1,
       1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0,
       1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1,
       0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
       0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0,
       0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0,
       1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1,
       0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
       0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0,
       0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1,
       0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1,
       1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1,
       0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1,
       0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1,
       0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1,
       1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1,
       1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
       0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0,
       0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0,
       1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1,
       1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0,
       0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0,
       0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0,
       0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0,
       1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,
       0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0,
       0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1,
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0,
       1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1,
       0, 0, 0, 0, 0, 0, 0, 0], dtype=int64)
'''
#输出随机森林的预测结果
rfc2.predict(X_train)
'''
array([0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1,
       1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0,
       1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1,
       0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1,
       0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0,
       1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0,
       0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
       0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0,
       0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1,
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
       1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0,
       0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
       0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1,
       0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1,
       0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1,
       1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
       0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0,
       0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0,
       1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1,
       0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0,
       0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0,
       1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0,
       1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0,
       0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0,
       1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1,
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0,
       1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0,
       0, 0, 0, 0, 0, 0, 0, 0], dtype=int64)
'''
#逻辑回归与随机森林预测相同率
sum(rfc2.predict(X_train)==pred)/len(rfc2.predict(X_train)==pred)
#0.9026946107784432
#逻辑回归预测概率,第一列为预测为0的概率
pred_proba = lr.predict_proba(X_train)
pred_proba
'''
array([[0.5983501 , 0.4016499 ],
       [0.12785797, 0.87214203],
       [0.46238894, 0.53761106],
       ...,
       [0.93827246, 0.06172754],
       [0.93993416, 0.06006584],
       [0.8815433 , 0.1184567 ]])
'''
#随机森林预测概率,,第一列为预测为0的概率
rfc.predict_proba(X_train)
array([[0.78, 0.22],
       [0.01, 0.99],
       [0.98, 0.02],
       ...,
       [0.82, 0.18],
       [0.91, 0.09],
       [0.95, 0.05]])

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

  • 可用来调整正负案例切分点
  • 对于某些应用场景,如违约预测,输出的概率可以作为客户是好是坏的概率。

模型评估

模型评估的方法

K折交叉验证

交叉验证再前面部分已经有过介绍,现在具体来实现:
在这里插入图片描述

#导入交叉验证模块
from sklearn.model_selection import cross_val_score
'''
cross_val_score(
    estimator,
    X,
    y=None,
    groups=None,
    scoring=None,
    cv=None,
    n_jobs=None,
    verbose=0,
    fit_params=None,
    pre_dispatch='2*n_jobs',
    error_score=nan,
)
Docstring:
通过交叉验证评估分数

在用户指南<cross_validation>中阅读更多内容。

参量
----------
estimator:实现“ fit”的估计器对象
    用于拟合数据的对象。
X:类似数组
    要拟合的数据。可以是例如列表或数组。
y:类似数组,可选,默认:无
    在以下情况下要尝试预测的目标变量
    监督学习。
groups:类数组,形状为(n_samples,),可选
    将数据集拆分为时使用的样本的标签分组
    训练/测试集。仅与“ Group”:term:`cv`结合使用
    实例(例如GroupKFold类)。
scoring:字符串,可调用或无,可选,默认:无
    字符串(请参阅模型评估文档)或
    带签名的计分员可调用对象/函数
    ``scorer(estimator,X,y)``应该只返回
    一个值。

    类似于:cross_validate
    但只允许使用一个指标。

    如果为None,则使用估算器的默认计分器(如果有)。

cv:int,交叉验证生成器或可迭代的,可选的
    确定交叉验证拆分策略。
    简历的可能输入是:

    -无,要使用默认的5倍交叉验证,
    -整数,用于指定“(分层)KFold”中的折叠次数,
    -:CV splitter`,
    -可迭代的屈服(训练,测试)拆分为索引数组。

    对于整数/无输入,如果估计量是分类器,而y是
    二进制或多类,都使用StraifiedKFold。在所有
    在其他情况下,使用KFold类。

    有关各种信息,请参考:用户指南<cross_validation>。
    可以在此处使用的交叉验证策略。

    ..版本已更改:: 0.22
        如果无从3倍更改为5倍,则为cv默认值。

n_jobs:int或None,可选(默认=无)
    用于进行计算的CPU数量。
    除非在:obj:`joblib.parallel_backend`上下文中,否则“ None``表示1。
    -1表示使用所有处理器。请参阅术语表<n_jobs>
    更多细节。

verbose:整数,可选
    详细程度。

fit_params:dict,可选
    传递给估算器的fit方法的参数。

pre_dispatch:int或字符串,可选
    控制并行期间调度的作业数
    执行。减少此数字可能有助于避免
    调度更多作业时内存消耗激增
    比CPU可以处理的多该参数可以是:

        -无,在这种情况下,所有作业都将立即执行
          创建并产生。将此用于轻便和
          快速运行的作业,以避免因按需而造成的延迟
          产生工作

        -一个整数,给出确切的总职位数
          产生

        -字符串,根据n_jobs给出表达式,
          如“ 2 * n_jobs”

error_score:“提高”或数字
    如果估算器拟合出现错误,则分配给分数的值。
    如果设置为“ raise”,则会引发错误。
    如果给出数值,则引发FitFailedWarning。这个参数
    不会影响改装步骤,因为它总是会引发错误。

return
-------
scores:浮点数组,形状=(len(list(cv)),)
    每次交叉验证的估算器得分数组。
'''
#对逻辑回归进行交叉验证
scores = cross_val_score(lr, X_train, y_train, cv=10)
#array([0.8358209 , 0.7761194 , 0.82089552, 0.80597015, 0.85074627,
#       0.86567164, 0.73134328, 0.86567164, 0.75757576, 0.71212121])
print("Average cross-validation score: {:.2f}".format(scores.mean()))
#Average cross-validation score: 0.80
#随机森林进行交叉验证
scores1 = cross_val_score(rfc2, X_train, y_train, cv=10)
#array([0.85074627, 0.80597015, 0.85074627, 0.7761194 , 0.82089552,
#       0.8358209 , 0.76119403, 0.80597015, 0.74242424, 0.75757576])
print("Average cross-validation score1: {:.2f}".format(scores1.mean()))
#Average cross-validation score1: 0.80
混淆矩阵极其衍生指标

在分类任务中,模型的预测结果可以分为四类:

  • 真正类:True Positive,TP ,正类预测为正类
  • 假负类:False Negative ,FN,正类预测为负类
  • 假正类:False Positive,FP,负类预测为正类
  • 真负类:True Negative,TN,负类预测为负类

上述四类预测结果可以组成如下混淆矩阵:

混淆矩阵样本正类Positive样本负类Negative
预测正类TrueTPFP
预测负类FalseFNTN

由以上四个指标可以衍生出准确率、召回率、精确度,其中:
准确率(Accuracy),表示分类问题中,正确预测的占总体的百分比:
A c c u r a c y = T P + T N T P + F P + F N + T N Accuracy=\cfrac{TP+TN}{TP+FP+FN+TN} Accuracy=TP+FP+FN+TNTP+TN
召回率(Recall),表示正例中有多少能正确预测,也叫查全率:
R e c a l l = T P T P + F N Recall=\cfrac{TP}{TP+FN} Recall=TP+FNTP
精确度(Precision),表示预测为正例中实际是正例的比例:
P r e c i s i o n = T P T P + F P Precision=\cfrac{TP}{TP+FP} Precision=TP+FPTP
值得注意的是召回率(Recall)和精确度(Precision)是一对矛盾的度量,通常精确率高时召回率低,召回率高时精确率低。
还可定义P-R曲线:
在上一部分内容中,分类算法预测的结果如下:
在这里插入图片描述
其中第一列为预测为0的概率,第二列为预测为1的概率,我们可以选择其中一列,假如选择第一列,对预测结果进行降序排序,以当前概率阈值,大于该阈值的样本预测为正例(正例标签为0),逐个计算当前召回率和精确率。再以召回率横坐标精确率纵坐标,绘制各点连接成线。
在这里插入图片描述
P-R曲线可以直观的显示分类模型在总体样本上的精确率召回率,也可以对比多个分类模型的型内,从上图可以看出A模型优于B、C模型。图中的平衡点是精确率=召回率时各自的取值平衡点离原点越远越好

import  matplotlib.pyplot as plt
res1=pd.DataFrame(pred_proba[:,1],y_train)
res1.reset_index(inplace=True)
res1.columns=['y','y_prob']
res1.sort_values(by='y_prob',ascending=False,inplace=True)
def P_R(data):
        '''
        data中需要有y列和y_prob列
        '''
    def pred_value(data,yuzhi):
        data['y_pred'+str(yuzhi)]=data['y_prob'].map(lambda x: 1 if x>=yuzhi else 0)
    for i in data.y_prob:
        pred_value(data,i)
    def precision(y_true,y_pred):
        true_positive=sum(y and y_p for y,y_p in zip(y_true,y_pred))
        predicted_positive=sum(y_pred)
        return true_positive/predicted_positive
    def recall(y_true,y_pred):
        true_positive=sum(y and y_p for y,y_p in zip(y_true,y_pred))
        real_positive=sum(y_true)
        return true_positive/real_positive
    P=[]
    R=[]
    for i in data.columns[2:]:
        p=precision(data['y'],data[i])
        P.append(p)
        r=recall(data['y'],data[i])
        R.append(r)
        plt.plot(R,P,'b')
        plt.plot([0,1],[0,1],'k--')
        plt.xlabel("Recall Rate")
        plt.ylabel("Precision Rate")
        plt.title("P-R Curve")
    plt.show()
P_R(res1)

逻辑回归的P-R曲线如下:
在这里插入图片描述

res2=pd.DataFrame(rfc2.predict_proba(X_train)[:,1],y_train)
res2.reset_index(inplace=True)
res2.columns=['y','y_prob']
res2.sort_values(by='y_prob',ascending=False,inplace=True)
P_R(res2)

随机森林P_R曲线如下:
在这里插入图片描述
从上述两图可以看出随机森林模型效果优于逻辑回归模型效果。
第二种方法

#逻辑回归
from sklearn.metrics import precision_recall_curve
precisions, recalls, thresholds = precision_recall_curve(y_train, lr.predict_proba(X_train)[:,1])
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.xlabel("Threshold")
    plt.legend(loc = "upper left")
    plt.ylim([0,1])
    
plot_precision_recall_vs_threshold(precisions, recalls, thresholds)
plt.show()

在这里插入图片描述
可以看出在划分阈值为0.5左右时逻辑回归模型取得最优效果,此时精确率和召回率约为0.72

#随机森林
from sklearn.metrics import precision_recall_curve
precisions, recalls, thresholds = precision_recall_curve(y_train, rfc2.predict_proba(X_train)[:,1])
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.xlabel("Threshold")
    plt.legend(loc = "upper left")
    plt.ylim([0,1])
    
plot_precision_recall_vs_threshold(precisions, recalls, thresholds)
plt.show()

在这里插入图片描述
可以看出在划分阈值为0.4左右时随机森林模型取得最优效果,此时精确率和召回率约为0.8.

另外一种方法是比较平衡点,就是上图中红色虚线与蓝色实线交叉点,此时精确率等于召回率
有如下定义:
2 F 1 = 1 P + 1 R F 1 = 2 T P 2 T P + F P + F N \cfrac{2}{F_1}=\cfrac{1}{P}+\cfrac{1}{R} \\ F_1=\cfrac{2TP}{2TP+FP+FN} F12=P1+R1F1=2TP+FP+FN2TP

实例

逻辑回归混淆矩阵

from sklearn.metrics import confusion_matrix
'''
confusion_matrix(
    y_true,
    y_pred,
    labels=None,
    sample_weight=None,
    normalize=None,
)
参数
----------
y_true:形状类似数组的形状(n_samples,)
     基本事实(正确)目标值。

y_pred:形状类似数组的形状(n_samples,)
     分类器返回的估计目标。

labels:形状类似数组(n_classes),默认=无
     索引矩阵的标签列表。 这可以用来重新排序
     或选择标签的子集。
     如果给出``无'',则至少出现一次的那些
     y_true或y_pred中的字母按排序顺序使用。

sample_weight:形状类似数组的形状(n_samples,),默认=无
     样品重量。

normalize:{'true','pred','all'},默认=无
     在真实(行),预测(列)上标准化混淆矩阵
     条件或全部人口。 如果为None,则混淆矩阵将为
     标准化。

return
-------
C:形状的ndarray(n_classes,n_classes)
     混淆矩阵。
     '''
confusion_matrix(y_train, lr.predict(X_train))
#array([[354,  58],
#       [ 72, 184]], dtype=int64)
import seaborn as sns
plt.figure(figsize=(8,6))
sns.heatmap(confusion_matrix(y_train, lr.predict(X_train)),annot=True,cmap='Blues')
plt.xlabel('Predicted labels')
plt.ylabel('True labels')
plt.show()

在这里插入图片描述
随机森林混淆矩阵

import seaborn as sns
plt.figure(figsize=(8,6))
sns.heatmap(confusion_matrix(y_train, rfc.predict(X_train)),annot=True,cmap='Blues')
plt.xlabel('Predicted labels')
plt.ylabel('True labels')
plt.show()

在这里插入图片描述

from sklearn.metrics import classification_report
#逻辑回归精确率、召回率、f1
print(classification_report(y_train, pred))
'''
              precision    recall  f1-score   support

           0       0.83      0.86      0.84       412
           1       0.76      0.72      0.74       256

    accuracy                           0.81       668
   macro avg       0.80      0.79      0.79       668
weighted avg       0.80      0.81      0.80       668
'''
#随机森林精确率、召回率、f1
print(classification_report(y_train, rfc2.predict(X_train)))
'''
              precision    recall  f1-score   support

           0       0.85      0.95      0.90       412
           1       0.90      0.74      0.81       256

    accuracy                           0.87       668
   macro avg       0.87      0.84      0.85       668
weighted avg       0.87      0.87      0.86       668
'''
ROC曲线

ROC曲线的横坐标是假正例率(FPR),纵坐标是真正例率(TPR),其中, T P R = T P T P + F N = 正 类 的 召 回 率 F P R = F P T N + F P = 1 − 负 类 召 回 率 TPR=\cfrac{TP}{TP+FN}=正类的召回率 \\ FPR=\cfrac{FP}{TN+FP}=1-负类召回率 TPR=TP+FNTP=FPR=TN+FPFP=1实践中可从sklearn.metrics调用roc_curve函数

#导入ROC曲线数据计算函数和AUC计算函数
from sklearn.metrics import roc_curve,roc_auc_score 
#逻辑回归
fpr, tpr, thresholds = roc_curve(y_test, lr.decision_function(X_test))
auc=roc_auc_score(y_test, lr.decision_function(X_test))
plt.plot(fpr, tpr, label="ROC Curve")
plt.plot([0,1],[0,1],'k--')
plt.xlabel("FPR")
plt.ylabel("TPR (recall)")
plt.title("ROC Curve The AUC ={}".format(round(auc,2)))
# 找到最接近于0的阈值
close_zero = np.argmin(np.abs(thresholds))
plt.plot(fpr[close_zero], tpr[close_zero], 'o', markersize=10, label="threshold zero", fillstyle="none", c='k', mew=2)
plt.legend(loc=4)

在这里插入图片描述

#导入ROC曲线数据计算函数和AUC计算函数
from sklearn.metrics import roc_curve,roc_auc_score 
#随机森林
#随机森林中没有decision_function函数直接用predict_proba替代,但thresholds无效
fpr, tpr, thresholds = roc_curve(y_test, rfc2.predict_proba(X_test)[:,1])
auc=roc_auc_score(y_test, rfc2.predict_proba(X_test)[:,1])
plt.plot(fpr, tpr, label="ROC Curve")
plt.plot([0,1],[0,1],'k--')
plt.xlabel("FPR")
plt.ylabel("TPR (recall)")
plt.title("ROC Curve The AUC ={}".format(round(auc,2)))
# 找到最接近于0的阈值
close_zero = np.argmin(np.abs(thresholds))
plt.plot(fpr[close_zero], tpr[close_zero], 'o', markersize=10, label="threshold zero", fillstyle="none", c='k', mew=2)
plt.legend(loc=4)

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值