机器学习Sklearn Day5

05 sklearn中的逻辑回归

1概述

1.1名为回归的分类器

1.2为什么需要逻辑回归

1.3 sklearn中的逻辑回归

2linear_model.LogisticRegression

2.1 二元逻辑回归的损失函数

2.1.1损失函数的概念与解惑

2.1.2【选学】二元逻辑回归损失函数的数学解释,公式推导与解惑

2.2重要参数penalty & C

2.2.1正则化

2.2.2逻辑回归中的特征工程

2.3梯度下降:重要参数max_iter

2.3.1 梯度下降求解逻辑回归

2.3.2 梯度下降的概念与解惑

2.3.4 步长的概念与解惑

2.4二元回归与多元回归:重要参数solver & multi_class

2.5样本不平衡与参数class_weight

3 案例:用逻辑回归制作评分卡

3.1导库,获取数据

3.2探索数据与数据预处理

3.2.1去除重复值

3.2.2 填补缺失值

3.2.3 描述性统计处理异常值

3.2.4 为什么不统一量纲,也不标准化数据分布?

3.2.5 样本不均衡问题

3.2.6 分训练集和测试集

3.3分箱

3.3.1 等频分箱

3.3.2 【选学】 确保每个箱中都有01

3.3.3 定义WOEIV函数

3.3.4 卡方检验,合并箱体,画出IV曲线

3.3.5 用最佳分箱个数分箱,并验证分箱结果

3.3.6 将选取最佳分箱个数的过程包装为函数

3.3.7对所有特征进行分箱选择

3.4 计算各箱的WOE并映射到数据中

3.5 建模与模型验证

3.6 制作评分卡

4附录:

4.1 逻辑回归的参数列表

4.2 逻辑回归的属性列表

4.3 逻辑回归的接口列表

1.概述

1.1 名为回归的分类器

在过去的四周中,我们接触了不少带回归二字的算法,回归树,随机森林的回归,无一例外他们都是区别于分类  算法们,用来处理和预测连续型标签的算法。然而逻辑回归,是一种名为回归线性分类器,其本质是由线性回  归变化而来的,一种广泛使用于分类问题中的广义回归算法。要理解逻辑回归从何而来,得要先理解线性回归。线  性回归是机器学习中最简单的的回归算法,它写作一个几乎人人熟悉的方程:

 

这个表达式,其实就和我们小学时就无比熟悉 y = ax+b  是同样的性质。我们可以使用矩阵来表示这个方程,其中xθ都可以被看做是一个列矩阵,则有:

 

 

 

面试高危问题:Sigmoid函数的公式和性质

Sigmoid函数是一个S的函数,当自变量z趋近正无穷时,因变量g(z)趋近于1,而当z趋近负无穷时,g(z)趋近于0,它能够将任何实数映射到(0,1)区间,使其可用于将任意值函数转换为更适合二分类的函数

因为这个性质,Sigmoid函数也被当作是归一化的一种方法,与我们之前学过的MinMaxSclaer同理,是属于数据预处理中的缩放功能,可以将数据压缩到[0,1]之内。区别在于,MinMaxScaler归一化之后,是可以取01的(最大值归一化后就是1,最小值归一化后就是0),但Sigmoid函数只是无限趋近于01取不到0和1

 

 

 

不难发现,y(x)的形似几率取对数的本质其实就是我们的线性回归z,我们实际上是在对线性回归模型的预测结果取    对数几率来让其的结果无限逼近01。因此,其对应的模型被称为对数几率回归logistic Regression),也就是我们的逻辑回归,这个名为回归却是用来做分类工作的分类器

之前我们提到过,线性回归核心任务求解θ构建z这个预测函数,并希望预测函数z能够尽量拟合数据,因此逻辑回归的核心任务也是类似的:求解θ来构建一个能够尽量拟合数据的预测函数y(x),并通过向预测函数中输入特征矩阵来获取相应的标签纸值y

 

1.2 为什么需要逻辑回归

线性回归对数据的要求很严格,比如标签必须满足正态分布,特征之间的多重共线性需要消除等等,而现实中很多  真实情景的数据无法满足这些要求,因此线性回归在很多现实情境的应用效果有限逻辑回归是由线性回归变化而  ,因此它对数据也有一些要求,而我们之前已经学过了强大的分类模型决策树和随机森林,它们的分类效力很     强,并且不需要对数据做任何预处理。

何况,逻辑回归的原理其实并不简单。一个人要理解逻辑回归,必须要有一定的数学基础,必须理解损失函数,正  则化,梯度下降,海森矩阵等等这些复杂的概念,才能够对逻辑回归进行调优。其涉及到的数学理念,不比支持向  量机少多少。况且,要计算概率,朴素贝叶斯可以计算出真正意义上的概率,要进行分类,机器学习中能够完成二  分类功能的模型简直多如牛毛。因此,在数据挖掘,人工智能所涉及到的医疗,教育,人脸识别,语音识别这些领  域,逻辑回归没有太多的出场机会。

甚至,在我们的各种机器学习经典书目中,周志华的《机器学习》400页仅有一页纸是关于逻辑回归的(还是一页    数学公式),《数据挖掘导论》和《Python数据科学手册》中完全没有逻辑回归相关的内容,sklearn中对比各种      分类器的效应也不带逻辑回归玩,可见业界地位。

但是,无论机器学习领域如何折腾,逻辑回归依然是一个受工业商业热爱,使用广泛的模型,因为它有着不可替代  的优点:

  1. 逻辑回归对线性关系的拟合效果好到丧心病狂特征与标签之间的线性关系极强的数据,比如金融领域中的    信用卡欺诈,评分卡制作,电商中的营销预测等等相关的数据,都是逻辑回归的强项。虽然现在有了梯度提    升树GDBT,比逻辑回归效果更好,也被许多数据咨询公司启用,但逻辑回归在金融领域,尤其是银行业中的    统治地位依然不可动摇(相对的,逻辑回归在非线性数据的效果很多时候比瞎猜还不如,所以如果你已经知    道数据之间的联系是非线性的,千万不要迷信逻辑回归)
  2. 逻辑回归返回的分类结果不是固定的01,而是以小数形式呈现的类概率数字:我们因此可以把逻辑回归返  回的结果当成连续型数据来利用。比如在评分卡制作时,我们不仅需要判断客户是否会违约,还需要给出确   定的信用分,而这个信用分的计算就需要使用类概率计算出的对数几率,而决策树和随机森林这样的分类   器,可以产出分类结果,却无法帮助我们计算分数(当然,在sklearn中,决策树也可以产生概率,使用接口predict_proba调用就好,但一般来说,正常的决策树没有这个功能)。返回概率一般用逻辑回归
  3. 逻辑回归计算快:对于线性数据,逻辑回归的拟合和计算都非常快计算效率优于SVM和随机森林,亲测表   示在大型数据上尤其能够看得出区别

另外,逻辑回归还有抗噪能力强的优点。福布斯杂志在讨论逻辑回归的优点时,甚至有着技术上来说,最佳模型   的AUC面积低于0.8时,逻辑回归非常明显优于树模型的说法。并且,逻辑回归在小数据集上表现更好,在大型的    数据集上,树模型有着更好的表现。逻辑回归小数据集表现更好,树模型大数据集表现更好

由此,我们已经了解了逻辑回归的本质,它是一个返回对数几率的,在线性数据上表现优异的分类器,它主要被应  用在金融领域。其数学目的是求解能够让模型对数据拟合程度最高的参数  θ(模型的参数)的值,以此构建预测函y(x),然后将特征矩阵输入预测函数来计算出逻辑回归的结果y。注意,虽然我们熟悉的逻辑回归通常被用于处理二分类问题但逻辑回归也可以做多分类。

1.3 sklearn中的逻辑回归

逻辑回归相关的类

说明

linear_model.LogisticRegression

逻辑回归分类器(又叫logit回归,最大熵分类器)

linear_model.LogisticRegressionCV

带交叉验证的逻辑回归分类器

linear_model.logistic_regression_path

计算Logistic回归模型以获得正则化参数的列表

linear_model.SGDClassifier

利用梯度下降求解的线性分类器(SVM,逻辑回归等等)

linear_model.SGDRegressor

利用梯度下降最小化正则化后的损失函数的线性回归模型

metrics.log_loss

对数损失,又称逻辑损失或交叉熵损失

【在sklearn0.21版本中即将被移除】

linear_model.RandomizedLogisticRegression

随机的逻辑回归

其他会涉及的类

说明

metrics.confusion_matrix

混淆矩阵,模型评估指标之一

metrics.roc_auc_score

ROC曲线,模型评估指标之一

metrics.accuracy_score

精确性,模型评估指标之一

2 linear_model.LogisticRegression

class sklearn.linear_model.LogisticRegression (penalty=’l2’, dual=False, tol=0.0001, C=1.0,

fit_intercept=True, intercept_scaling=1, class_weight=None, random_state=None, solver=’warn’, max_iter=100, multi_class=’warn’, verbose=0, warm_start=False, n_jobs=None)

2.1 二元逻辑回归的损失函数

2.1.1损失函数的概念与解惑

在学习决策树和随机森林时,我们曾经提到过两种模型表现:在训练集上的表现,和在测试集上的表现。我们建     模,是追求模型在测试集上的表现最优,因此模型的评估指标往往是用来衡量模型在测试集上的表现的。然而,逻  辑回归有着基于训练数据求解参数θ的需求并且希望训练出来的模型能够尽可能地拟合训练数据,即模型在训练集上的预测准确率越靠近100%越好

因此,我们使用损失函数这个评估指标,来衡量参数为θ的模型拟合训练集时产生的信息损失的大小,并以此衡量参数 θ  的优劣损失越大,参数θ越不好,损失越小,θ越好

如果用一组参数建模后,模型在训练集上表现良好,那我们就说模型拟合过程中的损失很小,损失函数的值很小,这一组参数就优秀;相反,如果模型在训练集上表现糟糕,损失函数就会很大,模型就训练不 足,效果较差,这一组参数也就比较差。即是说,我们在求解参数θ 时,追求损失函数最小,让模型在训练数据上的拟合效果最优,即预测准确率在训练集上尽量靠近100% 

 其中,θ表示求解出来的一组参数,m是样本的个数,y(i)样本i上真实的标签,yθ(Xi)是样本i上,基于参数θ 计算出来的逻辑回归返回值,Xi 是样本i各个特征的取值。我们的目标,就是求解出使J(θ)最小θ 取值

注意,在逻辑回归的本质函数y(x)里,特征矩阵x自变量参数是θ 。但在损失函数中,参数θ是损失函数的自变量xy都是知的特征矩阵和标签,相当于是损失函数的参数。不同的函数中,自变量和参数各有不同,因此大家需要在数学计算中,尤其是求导的时候避免混淆。

由于我们追求损失函数的最小值,让模型在训练集上表现最优,可能会引发另一个问题:如果模型在训练集上表示  优秀,却在测试集上表现糟糕,模型就会过拟合。虽然逻辑回归和线性回归是天生欠拟合的模型,但我们还是需要  控制过拟合的技术来帮助我们调整模型,对逻辑回归中过拟合的控制,通过正则化来实现

2.2 重要参数penalty & C

2.2.1 正则化

正则化是用来防止模型过拟合的过程,常用的有L1正则化L2正则化两种选项,分别通过在损失函数后加上参数    

θ 的L1范式和L2范式的倍数来实现。这个增加的范式,被称为正则项,也被称为"惩罚项"。损失函数改变,基于损失函数的最优化来求解的参数取值必然改变,我们以此来调节模型拟合的程度。其中L1范式表现为参数向量中  每个参数的绝对值之和L2范数表现为参数向量中的每个参数的平方和的开方值

 

 

其实和上面我们展示的式子的本质是一模一样的。不过在大多数教材和博客中,常数项是乘以正则项,通过调控正则项来调节对模型的惩罚。而sklearn当中,常数项C是在损失函数的前面,通过调控损失函数本身的大小,来调节对模型的惩罚

参数

说明

penalty

可以输入"l1""l2"来指定使用哪一种正则化方式,不填写默认"l2"

注意,若选择"l1"正则化,参数solver仅能够使用求解方式”liblinear""saga“,若使用“l2”正则化参数solver中所有的求解方式都可以使用。

C

C正则化强度的倒数,必须是一个大于0的浮点数,不填写默认1.0,即默认正则项与损失函数的   比值是11C越小,损失函数会越小,模型对损失函数的惩罚越重,正则化的效力越强,参数                      θ会逐渐被压缩得越来越小。  

L1正则化和L2正则化虽然都可以控制过拟合,但它们的效果并不相同。当正则化强度逐渐增大(即C逐渐变小),        参数θ的取值会逐渐变小,但L1正则化会将参数压缩为0L2正则化只会让参数尽量小,不会取到0

L1正则化在逐渐加强的过程中,携带信息量小的、对模型贡献不大的特征的参数,会比携带大量信息的、对模型   有巨大贡献的特征的参数更快地变成0,所以L1正则化本质是一个特征选择的过程,掌管了参数的稀疏性L1正     则化越强参数向量中就越多的参数为0,参数就越稀疏,选出来的特征就越少,以此来防止过拟合。因此,如果    特征量很大,数据维度很高,我们会倾向于使用L1正则化。由于L1正则化的这个性质,逻辑回归的特征选择可以由Embedded嵌入法来完成。

相对的,L2正则化在加强的过程中,会尽量让每个特征对模型都有一些小的贡献,但携带信息少,对模型贡献不大    的特征的参数会非常接近于0。通常来说,如果我们的主要目的只是为了防止过拟合,选择L2正则化就足够了。但    是如果选择L2正则化后还是过拟合,模型在未知数据集上的效果表现很差,就可以考虑L1正则化

L1正则化会选择特征,L2正则化不会去除特征,会尽量让每个特征参数都有一些贡献

而两种正则化下C的取值,都可以通过学习曲线来进行调整。

建立两个逻辑回归,L1正则化和L2正则化的差别就一目了然了:

#导库

from sklearn.linear_model import LogisticRegression as LR  #导入线性模型中的逻辑回归

from sklearn.datasets import load_breast_cancer   #导入乳腺癌数据集

import numpy as np  

import matplotlib.pyplot as plt

from sklearn.model_selection import train_test_split #分测试集和训练集的类

from sklearn.metrics import accuracy_score   #矩阵模块导入精确性分数

data = load_breast_cancer() #数据实例化

data   #查看数据,为字典形式

X = data.data   #特征矩阵

y = data.target  #标签矩阵

data.data.shape  #569行,30个特征(30不算高纬度,但在现实中已经算多(判断是否乳腺癌)

-->(560,30)

#逻辑回归探究自变量特征矩阵x和因变量y之间的关系

#penalty="l1",l1正则化,C=0.5,C越小,损失函数会越小,正则化越强,θ被压缩越小

lrl1 = LR(penalty="l1",solver="liblinear",C=0.5,max_iter=1000)

#penalty="l2",l2正则化,C=0.5

lrl2 = LR(penalty="l2",solver="liblinear",C=0.5,max_iter=1000)

lrl1 = lrl1.fit(X,y)  #l1正则化,训练数据

#逻辑回归的重要属性coef_,查看每个特征所对应的参数

lrl1.coef_

-->array([[ 3.98582021,  0.03120391, -0.13533332, -0.01617202,  0.        ,

         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,

         0.        ,  0.50195837,  0.        , -0.07119773,  0.        ,

         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,

         0.        , -0.24503043, -0.12814562, -0.01445104,  0.        ,

         0.        , -2.05723328,  0.        ,  0.        ,  0.        ]])

(lrl1.coef_ != 0).sum(axis=1)    #加和即不为0的系数有多少个,30个特征中有10个不为0

-->array([10]

lrl2 = lrl2.fit(X,y)   #l2正则化训练数据

lrl2.coef_

-->array([[ 1.61543234e+00,  1.02284415e-01,  4.78483684e-02,

        -4.43927107e-03, -9.42247882e-02, -3.01420673e-01,

        -4.56065677e-01, -2.22346063e-01, -1.35660484e-01,

        -1.93917198e-02,  1.61646580e-02,  8.84531037e-01,

         1.20301273e-01, -9.47422278e-02, -9.81687769e-03,

        -2.37399092e-02, -5.71846204e-02, -2.70190106e-02,

        -2.77563737e-02,  1.98122260e-04,  1.26394730e+00,

        -3.01762592e-01, -1.72784162e-01, -2.21786411e-02,

        -1.73339657e-01, -8.79070550e-01, -1.16325561e+00,

        -4.27661014e-01, -4.20612369e-01, -8.69820058e-02]])

可以看见,当我们选择L1正则化的时候,许多特征的参数都被设置为了0,这些特征在真正建模的时候,就不会出    现在我们的模型当中了,而L2正则化则是对所有的特征都给出了参数

究竟哪个正则化的效果更好呢?还是都差不多?

#***************学习曲线****************

l1 = []   #l1正则化下的训练

l2 = []   #l2正则化下的训练

l1test = []   #l1正则化下的测试

l2test = []   #l2正则化下的测试

#划分训练集,测试集

Xtrain, Xtest, Ytrain, Ytest = train_test_split(X,y,test_size=0.3,random_state=420)

#绘制C的学习曲线

#让C的值在0.05-1中取出19个数

for i in np.linspace(0.05,1,19):

    lrl1 = LR(penalty="l1",solver="liblinear",C=i,max_iter=1000)  #L1正则化回归

    lrl2 = LR(penalty="l2",solver="liblinear",C=i,max_iter=1000)  #L2正则化回归

    

    #l1正则化训练

    lrl1 = lrl1.fit(Xtrain,Ytrain)

    #accuracy_score准确率打分

    l1.append(accuracy_score(lrl1.predict(Xtrain),Ytrain))  #predict得到模型在训练过后对于输入的特征矩阵的预测 

    l1test.append(accuracy_score(lrl1.predict(Xtest),Ytest))

    

    #l2正则化训练

    lrl2 = lrl2.fit(Xtrain,Ytrain)

    l2.append(accuracy_score(lrl2.predict(Xtrain),Ytrain))

    l2test.append(accuracy_score(lrl2.predict(Xtest),Ytest))

graph = [l1,l2,l1test,l2test]

color = ["green","black","lightgreen","gray"]

label = ["L1","L2","L1test","L2test"]

plt.figure(figsize=(6,6))

for i in range(len(graph)):

    plt.plot(np.linspace(0.05,1,19),graph[i],color[i],label=label[i])

plt.legend(loc=4) #图例的位置在哪里?loc=4表示,右下角

plt.show()

 

可见,至少在我们的乳腺癌数据集下,两种正则化的结果区别不大训练集结果略好于测试集结果。但随着C的逐渐变大正则化的强度越来越     小,模型在训练集和测试集上的表现都呈上升趋势,直到C=0.8左右,训练集上的表现依然在走高,但模型在未知数据集上的表现开始下跌,这时候就是出现了过拟合。我们可以认为,C设定为0.8会比较好。在实际使用时,基本默认使用l2正则化,如果感觉到模型的效果不好,那就换L1试试看。

2.2.2 逻辑回归中的特征工程

特征的数量很多的时候,我们出于业务考虑,也出于计算量的考虑,希望对逻辑回归进行特征选择来降维。比     如,在判断一个人是否会患乳腺癌的时候,医生如果5~8个指标来确诊,会比需要看30个指标来确诊容易得多

·业务选择

说到降维特征选择,首先要想到的是利用自己的业务能力进行选择,肉眼可见明显和标签有关的特征就是需要留  下的。当然,如果我们并不了解业务,或者有成千上万的特征,那我们也可以使用算法来帮助我们。或者,可以让  算法先帮助我们筛选过一遍特征,然后在少量的特征中,我们再根据业务常识来选择更少量的特征。

·PCASVD一般不用因为逻辑回归需要判断特征与分类结果的关联系

说到降维,我们首先想到的是之前提过的高效降维算法,PCASVD,遗憾的是,这两种方法大多数时候不适用于    逻辑回归逻辑回归是由线性回归演变而来线性回归的一个核心目的通过求解参数来探究特征X标签y之间的   关系,而逻辑回归也传承了这个性质,我们常常希望通过逻辑回归的结果,来判断什么样的特征与分类结果相关,  因此我们希望保留特征的原貌PCASVD降维结果是不可解释的,因此一旦降维后,我们就无法解释特征和标    签之间的关系了。当然,在不需要探究特征与标签之间关系的线性数据上,降维算法PCASVD也是可以使用的。

·统计方法可以使用,但不是非常必要

既然降维算法不能使用,我们要用的就是特征选择方法。逻辑回归对数据的要求低于线性回归,由于我们不是使用  最小二乘法来求解,所以逻辑回归对数据的总体分布和方差没有要求,也不需要排除特征之间的共线性,但如果我  们确实希望使用一些统计方法,比如方差,卡方,互信息等方法来做特征选择,也并没有问题。过滤法中所有的方  ,都可以用在逻辑回归上。

在一些博客中有这样的观点:多重共线性会影响线性模型的效果。对于线性回归来说,多重共线性会影响比较大,  所以我们需要使用方差过滤和方差膨胀因子VIF(variance inflation factor)来消除共线性。但是对于逻辑回归,其实不是非常必要,甚至有时候,我们还需要多一些相互关联的特征来增强模型的表现。当然,如果我们无法通过其他  方式提升模型表现,并且你感觉到模型中的共线性影响了模型效果,那懂得统计学的你可以试试看用VIF消除共线    性的方法,遗憾的是现在sklearn中并没有提供VIF的功能。

轻松一刻

R vs Python,统计学 vs 机器学习

有许多学过R,或者和python一起学习R的小伙伴,曾向我问起各种各样的统计学问题,因为R中有各种各样的统计功能,而python的统计学功能并不是那么全面。我也曾经被小伙伴们发给我的“R风格python代码弄得晕头转向,也许R的代码希望看起来高大上,但python之美就是简单明P.S. Python开发者十分有情怀,在jupyter中输入 import this 可以查看python中隐含的彩蛋,python制作者所写的诗歌”python之禅,通篇赞美了python代码的简单,明快,容易阅读之美,大家感兴趣的可以百度搜一搜看看翻译)。

回归正题,为什么pythonR在统计学的功能上差异如此之大呢?也许大家听说过,R是学统计学的人开发的,因此整个思路都是统计学的思路,而python是学计算机的人开发的,因此整个思路都是计算机的思路,

也无怪R在处理统计问题上比python强很多了,这两种学科不同的思路强烈反应在统计学和机器学习的各种建模流程当中。

统计学的思路是一种先验的思路,不管做什么都要检验,先满足条件,事后也要各种检验,以确保各种数学假设被满足,不然的话,理论上就无法得出好结果。

机器学习是一种后验的思路,不管三七二十一,我先让模型跑一跑,效果不好我再想办法,如果模型效果好,我完全不在意什么共线性,残差不满足正态分布,没有哑变量之类的细节,模型效果好大过天!

我完全欣赏机器学习的这种后验路:我们追求结果,不要过于在意那些需要满足的先决条件。对我而言,统计学是机器学习穷尽所有手段都无法解决问题后的救星,如果机器学习不能解决问题,我会向统计学寻求帮助,但我绝不会一开始就想着要去满足各种统计要求。当然啦,如果大家是学统计学出身,写R出身,大家也可以把机器学习当成是统计学手段   用尽后的"救星"。统计学和机器学习是相辅相成的,大家要了解两种思路的不同,以便在进入死胡同的时候,可以从另一个学科的思路中找到出路。只要能够解决问题的,都是好思路!

·高效的嵌入法embedded

但是更有效的方法,毫无疑问会是我们的embedded嵌入法。我们已经说明了,由于L1正则化会使得部分特征对应的参数为0,因此L1正则化可以用来做特征选择结合嵌入法的模块SelectFromModel,我们可以很容易就筛选出让模型十分高效的特征。注意,此时我们的目的是,尽量保留原数据上的信息,让模型在降维后的数据上的拟合效  果保持优秀,因此我们不考虑训练集测试集的问题,把所有的数据都放入模型进行降维。

#导库

from sklearn.linear_model import LogisticRegression as LR  #逻辑回归

from sklearn.datasets import load_breast_cancer  #乳腺癌数据集

import numpy as np

import matplotlib.pyplot as plt

from sklearn.model_selection import cross_val_score   

from sklearn.feature_selection import SelectFromModel  #嵌入法

data = load_breast_cancer()  #数据实例化

data.data.shape   #569行,30个特征

-->(569, 30)

LR_ = LR(solver="liblinear",C=0.8,random_state=420)  #实例化模型,C=0.8结果较好

#参数(实例化模型,特征,标签,循环次数)

cross_val_score(LR_,data.data,data.target,cv=10).mean()

-->0.9508145363408522

#对数据进行降维,嵌入法实例化

#参数(实例化模型,threshold=某个浮点数:即特去除征重要性小于该数的(此处不行),norm_order=1就是使用L1范数进行筛选)

X_embedded = SelectFromModel(LR_,norm_order=1).fit_transform(data.data,data.target)

X_embedded.shape  #30个特征降到9个

-->(569, 9)

#交叉验证X_embedded

cross_val_score(LR_,X_embedded,data.target,cv=10).mean()   #结果没有下降太多,但特征数量减少到了9个

-->0.9368107769423559

看看结果,特征数量被减小到个位数,并且模型的效果却没有下降太多,如果我们要求不高,在这里其实就可以停下了。但是,能否让模型的拟合效果更好呢?在这里,我们有两种调整方式:

1) 调节SelectFromModel这个类中的参数threshold,这是嵌入法的阈值,表示删除所有参数的绝对值低于这个阈的特征。现在threshold默认为None,所以SelectFromModel只根据L1正则化的结果来选择了特征,即选择了所L1正则化后参数不为0的特征。我们此时,只要调整threshold的值(画出threshold的学习曲线),就可以观察不同的threshold下模型的效果如何变化。一旦调整threshold,就不是在使用L1正则化选择特征,而是使用模型的属性.coef_中生成的各个特征的系数来选择coef_虽然返回的是特征的系数,但是系数的大小和决策树中的feature_   importances_以及降维算法中的可解释性方差explained_vairance_概念相似,其实都是衡量特征的重要程度和贡献度的,因此SelectFromModel中的参数threshold可以设置为coef_的阈值,即可以剔除系数小于threshold中输入的数字的所有特征。

LR_.fit(data.data,data.target).coef_     #coef_返回系数越大,代表特征重要性越大

-->array([[ 1.94071925,  0.11027501, -0.02792478, -0.00347267, -0.13418458,

        -0.36887791, -0.58229351, -0.30118379, -0.19522369, -0.02391175,

        -0.01172073,  1.12398531,  0.04214842, -0.0940855 , -0.01457835,

        -0.00486005, -0.05146662, -0.03584081, -0.03757288,  0.0042326 ,

         1.24863871, -0.32757391, -0.13662037, -0.0236736 , -0.24820117,

        -1.05186104, -1.44596614, -0.57989786, -0.6022902 , -0.10544953]])

fullx = []   #完整的特征矩阵的效果

fsx = []     #特征选择后的特征矩阵的效果

#threshold阈值有正负,取绝对值最大值,从0到阈值最大值取20个数

threshold = np.linspace(0,abs((LR_.fit(data.data,data.target).coef_)).max(),20)

threshold  #绝对值后的系数

-->array([0.        , 0.10214312, 0.20428624, 0.30642935, 0.40857247,

       0.51071559, 0.61285871, 0.71500183, 0.81714495, 0.91928806,

       1.02143118, 1.1235743 , 1.22571742, 1.32786054, 1.43000366,

       1.53214677, 1.63428989, 1.73643301, 1.83857613, 1.94071925]

k=0

#遍历threshold

for i in threshold:

    X_embedded = SelectFromModel(LR_,threshold=i).fit_transform(data.data,data.target)

    fullx.append(cross_val_score(LR_,data.data,data.target,cv=5).mean())  #交叉验证完整的特征矩阵

    fsx.append(cross_val_score(LR_,X_embedded,data.target,cv=5).mean()) #交叉验证降维后的特征矩阵

    print((threshold[k],X_embedded.shape[1]))   #打印每一次threshold取到的每一个值以及降维后的特征矩阵含有多少特征

k+=1

-->(0.0, 30)

(0.1021431183124225, 17)

(0.204286236624845, 12)

(0.3064293549372675, 10)

(0.40857247324969, 8)

(0.5107155915621124, 8)

(0.612858709874535, 5)

(0.7150018281869575, 5)

(0.81714494649938, 5)

(0.9192880648118025, 5)

(1.0214311831242249, 5)

(1.1235743014366475, 4)

(1.22571741974907, 3)

(1.3278605380614925, 2)

(1.430003656373915, 2)

(1.5321467746863375, 1)

(1.63428989299876, 1)

(1.7364330113111823, 1)

(1.838576129623605, 1)

(1.9407192479360273, 1)

#绘制学习曲线

plt.figure(figsize=(20,5))  

plt.plot(threshold,fullx,label="full")  #完整的特征矩阵画的图

plt.plot(threshold,fsx,label="feature selection")   #降维后的特征矩阵画的图

plt.xticks(threshold)

plt.legend()

plt.show()

然而,这种方法其实是比较无效的,大家可以用学习曲线来跑一跑:threshold越来越大,被删除的特征越来越      多,模型的效果也越来越差,模型效果最好的情况下需要保证有17个以上的特征。实际上我画了细化的学习曲线,如果要保证模型的效果比降维前更好,我们需要保留25个特征,这对于现实情况来说,是一种无效的降维:需要30个指标来判断病情,和需要25个指标来判断病情,对医生来说区别不大

2)第二种调整方法,是调逻辑回归的类LR_,通过画C学习曲线来实现:

fullx = []  #完整特征矩阵

fsx = []    #降维后特征矩阵

C=np.arange(0.01,10.01,0.5)   #0.01-10.01每0.5取一个值

C

--array([0.01, 0.51, 1.01, 1.51, 2.01, 2.51, 3.01, 3.51, 4.01, 4.51, 5.01,

       5.51, 6.01, 6.51, 7.01, 7.51, 8.01, 8.51, 9.01, 9.51])

for i in C:

    LR_ = LR(solver="liblinear",C=i,random_state=420)  #实例化

    #完整特征矩阵交叉验证

    fullx.append(cross_val_score(LR_,data.data,data.target,cv=10).mean())  

    

    #特征选择后的特征矩阵交叉验证(l1范数)

    X_embedded = SelectFromModel(LR_,norm_order=1).fit_transform(data.data,data.target)

    fsx.append(cross_val_score(LR_,X_embedded,data.target,cv=10).mean())

print(max(fsx),C[fsx.index(max(fsx))])   #返回最大份数对应c的取值

#绘制c的学习曲线

plt.figure(figsize=(20,5))

plt.plot(C,fullx,label="full")

plt.plot(C,fsx,label="feature selection")

plt.xticks(C)

plt.legend()

plt.show()

0.9561090225563911 7.01

 

继续细化学习曲线:

fullx = []

fsx = []

C=np.arange(6.05,7.05,0.005)   #C从6.05-7.05 每隔0.005取值

for i in C:

    #实例化

    LR_ = LR(solver="liblinear",C=i,random_state=420)  

    #完整的特征矩阵交叉验证

    fullx.append(cross_val_score(LR_,data.data,data.target,cv=10).mean())

    #特征选择后特征矩阵交叉验证

    X_embedded = SelectFromModel(LR_,norm_order=1).fit_transform(data.data,data.target)

    fsx.append(cross_val_score(LR_,X_embedded,data.target,cv=10).mean())

print(max(fsx),C[fsx.index(max(fsx))])

-->0.9561090225563911 6.069999999999999

#绘制学习曲线

plt.figure(figsize=(20,5))

plt.plot(C,fullx,label="full")

plt.plot(C,fsx,label="feature selection")

plt.xticks(C)

plt.legend()

plt.show()

#验证模型效果:降维之前

LR_ = LR(solver="liblinear",C=6.069999999999999,random_state=420)

cross_val_score(LR_,data.data,data.target,cv=10).mean()

-->0.9473057644110275

#验证模型效果:降维之后

LR_ = LR(solver="liblinear",C=6.069999999999999,random_state=420)

X_embedded = SelectFromModel(LR_,norm_order=1).fit_transform(data.data,data.target)

cross_val_score(LR_,X_embedded,data.target,cv=10).mean()

-->0.9561090225563911       #高于降维前的结果

X_embedded.shape  #降到11个特征

-->(569, 11)


 

这样我们就实现了在特征选择的前提下,保持模型拟合的高效,现在,如果有一位医生可以来为我们指点迷津,看看剩下的这些特征中,有哪些是对针对病情来说特别重要的,也许我们还可以继续降维。当然,除了嵌入法,系数  累加法或者包装法也是可以使用的。

·比较麻烦的系数累加法

系数累加法的原理非常简单。在PCA中,我们通过绘制累积可解释方差贡献率曲线选择超参数,在逻辑回归中我们可以使用系coef_来这样做,并且我们选择特征个数的逻辑也是类似的:找出曲线由锐利变平滑的转折点折点之前被累加的特征都是我们需要的,转折点之后的我们都不需要。不过这种方法相对比较麻烦,

因为我们要先  特征系数进行从大到小的排序,还要确保我们知道排序后的每个系数对应的原始特征的位置,才能够正确找出那些重要的特征。如果要使用这样的方法不如直接使用嵌入法来得方便。

·简单快速的包装法

相对的,包装法可以直接设定我们需要的特征个数逻辑回归在现实中运用时,可能会有需要5~8个变量这种需    求,包装法此时就非常方便了。不过逻辑回归的包装法的使用和其他算法一样,并不具有特别之处,因此在这里就不在赘述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值