【菜菜·sklearn·ML笔记】逻辑回归(一)

【菜菜·sklearn·ML笔记】逻辑回归(一),第1张

目录

1.linear_model.LogisticRegression

1.1 重要参数 penalty & C

1.1.1 正则化

1.1.2 逻辑回归中的特征工程

1.2 重要参数 max_iter

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


首先来看一下sklearn中逻辑回归的类:

1.linear_model.LogisticRegression class sklearn.linear_model.LogisticRegression ( penalty=’l2’ , dual=False , tol=0.0001 , C=1.0 , fifit_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 ) 下面根据类中的各种重要参数进行讨论。


1.1 重要参数 penalty & C 1.1.1 正则化

常用的有L1正则化和L2正则化两种选项  penalty可以输入l1或者l2,从而告诉模型想用哪一种正则化方式,默认是l2;

C是正则化强度的倒数,大于0的浮点数,默认1.0,C越小,损失函数会越小,模型对损失函数的惩罚越重,正则化的效力越强,参数会逐渐被压缩得越来越小。


L1正则化会将参数压缩为0L2正则化只会让参数尽量小,不会取到0


下面看看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()
X = data.data
y = data.target
data.data.shape
lrl1 = LR(penalty="l1",solver="liblinear",C=0.5,max_iter=1000)
lrl2 = LR(penalty="l2",solver="liblinear",C=0.5,max_iter=1000) 
#逻辑回归的重要属性coef_,查看每个特征所对应的参数
lrl1 = lrl1.fit(X,y)
print(lrl1.coef_)
print((lrl1.coef_ != 0).sum(axis=1)) #可返回不为0的系数个数,等于=返回true;不等于返回false

lrl2 = lrl2.fit(X,y)
print(lrl2.coef_)  #l2不压缩特征,所有特征都有系数

打印L1正则化和L2正则化后每个参数的系数:

 下面探索哪种正则化效果更好:

l1 = []  #保存l1训练的结果
l2 = []
l1test = []
l2test = []
Xtrain, Xtest, Ytrain, Ytest = train_test_split(X,y,test_size=0.3,random_state=420)
for i in np.linspace(0.05,1,19):
    lrl1 = LR(penalty="l1",solver="liblinear",C=i,max_iter=1000)
    lrl2 = LR(penalty="l2",solver="liblinear",C=i,max_iter=1000)
    
    lrl1 = lrl1.fit(Xtrain,Ytrain)
    l1.append(accuracy_score(lrl1.predict(Xtrain),Ytrain))
    l1test.append(accuracy_score(lrl1.predict(Xtest),Ytest))
    
    lrl2 = lrl2.fit(Xtrain,Ytrain)
    l2.append(accuracy_score(lrl2.predict(Xtrain),Ytrain))
    l2test.append(accuracy_score(lrl2.predict(Xtest),Ytest))

#设置中文字体
import matplotlib.font_manager as fm
my_font=fm.FontProperties(fname="/System/Library/Fonts/PingFang.ttc")

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) #图例的位置在哪里?4表示,右下角
plt.xlabel('C 的取值',fontproperties=my_font)
plt.ylabel('模型准确度',fontproperties=my_font)
plt.show()

上图显示两种正则化方式的模型在训练集表现都很好
随着C的逐渐变大,正则化的强度越来越小,模型在训练集和测试集上的表现都呈上升趋势,直到C=0.8左右,训练集上的表现依然在走高,但模型在未知数据集上的表现开始下跌,这时候就是出现了过拟合,在实际使用时,基本就默认使用l2正则化,如果感觉到模型的效果不好,那就换L1试试看。


1.1.2 逻辑回归中的特征工程
  • 为什么不用PCA
逻辑回归是由线性回归演变而来,线性回归的一个核心目的是通过求解参数来探究特征 X 与标签 y 之间的 关系,而逻辑回归也传承了这个性质,我们常常希望通过逻辑回归的结果,来判断什么样的特征与分类结果相关, 因此我们希望保留特征的原貌。


PCA SVD 的降维结果是不可解释的,因此一旦降维后,我们就无法解释特征和标 签之间的关系了。


推荐使用高效的嵌入法embedded

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
LR_ = LR(solver="liblinear",C=0.9,random_state=420)
print(cross_val_score(LR_,data.data,data.target,cv=10).mean())
X_embedded = SelectFromModel(LR_,norm_order=1).fit_transform(data.data,data.target)
print(X_embedded.shape)

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

看看结果,特征数量被减小到个位数,并且模型的效果却没有下降太多,如果我们要求不高,在这里其实就可以停下了。


想让模型效果更好,有两种调节方式:

(1)调节SelectFromModel中的threshold

只要调整threshold的值(画出threshold的学习曲线),就可以观察不同的threshold下模型的效果如何变化。


一旦调整threshold,就不是在使用L1正则化选择特征,而是使用模型的属性.coef_中生成的各个特征的系数来选择。


coef_虽然返回的是特征的系数,但是系数的大小和决策树中的feature_ importances_以及降维算法中的可解释性方差explained_vairance_概念相似,其实都是衡量特征的重要程度和贡献度的,因此SelectFromModel中的参数threshold可以设置为coef_的阈值,即可以剔除系数小于threshold中输入的数字的所有特征。


fullx = []
fsx = []
threshold = np.linspace(0,abs((LR_.fit(data.data,data.target).coef_)).max(),20)
k=0 #abs代表对里面的系数取绝对值
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]))
    k+=1

plt.figure(figsize=(20,5))
plt.plot(threshold,fullx,label="full")
plt.plot(threshold,fsx,label="feature selection")
plt.xticks(threshold)
plt.xlabel('threshold 的取值',fontproperties=my_font)
plt.ylabel('模型交叉验证得分',fontproperties=my_font)
plt.legend()
plt.show()

 然而,这种方法其实是比较无效的
当threshold越来越大,被删除的特征越来越多,模型的效果也越来越差,模型效果最好的情况下需要保证有17个以上的特征。



这对于现实情况来说,是一种无效的降维

(2)调逻辑回归的类LR_

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

fullx = []
fsx = []
C=np.arange(0.01,10.01,0.5)
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))])
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()

继续细化学习曲线

#细化学习曲线
fullx = []
fsx = []
C=np.arange(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))])
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()
print("降维后数据集结构为:",X_embedded.shape) #(569, 11)
1.2 重要参数 max_iter

关于max_iter设置成多少可以达到较好的效果,通过学习曲线展示:

l2 = [] #训练集上的测试结果
l2test = [] #测试集上测试结果
Xtrain, Xtest, Ytrain, Ytest = train_test_split(X,y,test_size=0.3,random_state=420)

for i in np.arange(1,201,10):
    lrl2 = LR(penalty="l2",solver="liblinear",C=0.9,max_iter=i)
    lrl2 = lrl2.fit(Xtrain,Ytrain)
    l2.append(accuracy_score(lrl2.predict(Xtrain),Ytrain))
    l2test.append(accuracy_score(lrl2.predict(Xtest),Ytest))
    
graph = [l2,l2test]
color = ["black","gray"]
label = ["L2","L2test"]

plt.figure(figsize=(20,5))
for i in range(len(graph)):
    plt.plot(np.arange(1,201,10),graph[i],color[i],label=label[i])

plt.legend(loc=4)
plt.xticks(np.arange(1,201,10))
plt.xlabel('max_iter')
plt.ylabel('cv结果',fontproperties=my_font)
plt.show()

#使用属性.n_iter_来调用本次求解中真正实现的迭代次数
lr = LR(penalty="l2",solver="liblinear",C=0.9,max_iter=100).fit(Xtrain,Ytrain)
print(lr.n_iter_)  #24

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

把某种分类类型都看作1,其余的分类类型都为0值,这种方法被称为"一对多"(One-vs-rest),简称OvR,在sklearn中表示为“ovr"

又或者,我们可以把 好几个分类类型划为1,剩下的几个分类类型划为0值,这是一种多对多“(Many-vs-Many)的方法,简称MvM,在 sklearn中表示为"Multinominal"

每种方式都配合L1L2正则项来使用。


sklearn中,使用参数multi_class来告诉模型,我们的预测标签是ovr还是MvM

 看看鸢尾花数据集上,multinomial和ovr的区别:

from sklearn.datasets import load_iris
iris = load_iris()
print(iris.target)

for multi_class in ('multinomial', 'ovr'):
    clf = LR(solver='sag', max_iter=100, random_state=42,
                             multi_class=multi_class).fit(iris.data, iris.target) 
    print("training score : %.3f (%s)" % (clf.score(iris.data, iris.target), multi_class))
    
#training score : 0.987 (multinomial)
#training score : 0.960 (ovr)

   结果是多对多的效果更好

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/568684.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-09
下一篇 2022-04-09

发表评论

登录后才能评论

评论列表(0条)

保存