Logistic模型及其Scikit-learn实现

  • 概述
      Logistic回归属于概率型非线性回归,主要用于解决线性可分的分类问题。该模型利用函数Logistic function将单次实验的可能结果输出为概率。当变量之间存在多重共线性的,逻辑回归模型非常容易过拟合,此时用最小二乘估计的回归系数将会变得不准确,可采用岭回归和主成分回归来消除多重共线的参数。
      接下来讨论二分类情况下的Logistic回归的算法原理。二分类情况下,逻辑回归模型的因变量只有两个取值”是“和”否“,记为。假设在自变量的作用下,因变量取“是”的概率是p,则取“否“的概率是1-p。逻辑回归研究的就是当因变量为p时,p与自变量的关系。由于,而。现在想要找到一个映射将变量映射到之间,显然这样的映射是存在并且存在很多。
      Logistic模型采用了另一种方式,它通过构造p的对数几率,通过寻找与之间的关系,将问题转化为我们最为熟悉的多元线性回归模型求解问题。这也是在进行理论研究时惯用的思路:对于陌生领域的问题,将其转化为我们已知且熟悉的领域,用已建立的成熟体系去研究并解决这些问题。

几率:如果事情A发生的概率为p,则将比值称之为事件A发生的几率。

言归正传,现在,只需估计多元线性回归模型的参数即可得到概率:

也就是取1的概率,其中

得到:

p的函数图像如下:

Logistic曲线

在此使用极大似然估计法来进行参数的估计。为方便计算令,则,得到似然函数:

为方便计算,取自然对数得:


整理得:

对数似然函数取最大值的求解,一般来说将对数似然函数的相反数(NLL)作为模型的损失函数:

此时可使用梯度下降法求解NLL的最小值,得到的值为了解决Logistic模型的过拟合问题可使用带正则项的损失函数。这点不再做详细讨论,可参考Logistic for sklearn。

  • 实际应用
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=N
one,solver='liblinear',max_iter=100,multi_class='ovr',verbose=0,warm_start=False,n_jobs=1)

penalty:正则化参数,可选l1或l2,分别对应l1正则化和l2正则化,默认为l2正则化。一般来说l2正则化可以处理大部分的过拟合问题,如果模型的泛化能力仍然较差或者模型的特征较多,需要过滤掉一些不重要的特征时,可考虑用l1正则化。penalty参数的选择还会影响损失函数优化算法即参数solver的选择,当使用l2正则化时,优化算法 {‘newton-cg’, ‘lbfgs’, ‘liblinear’, ‘sag’}都可以使用。当penalty是L1正则化的话,就只能选择‘liblinear’了。这是因为L1正则化的损失函数不是连续可导的,而{‘newton-cg’, ‘lbfgs’,‘sag’}这三种优化算法时都需要损失函数的一阶或者二阶连续导数,‘liblinear’则不需要。

  监督算法在拟合过程中为了尽可能的兼顾每个数据,可能会导致模型泛化能力(模型应用到新样本的能力)较差,最直观的表现就是模型参数过于复杂,将这种情况成为模型的过拟合,一般发生在变量过多的时候。过拟合问题,一般有两种处理思路:

  • 减少变量个数
      保留更为重要的特征,舍弃一些不重要的特征,PCA是比较主流处理方式。
  • 正则化
      在模型的误差函数中加上惩罚项,使得新的误差函数:

    当时称之为l1正则化;时称之为l2正则化,其实质就是当变量过多时,其范数会较大,此时通过调整使得惩罚项进一步变大,而为了保持误差函数最小,只能减小变量的参数的值,也就是所谓的对参数进行‘惩罚’,当足够大时,某些变量对应的参数减小到0或者接近0可以直接舍弃,起到减少模型中的变量个数的作用。

dual:用来指明是否将原问题改成他的对偶问题,对偶问题可以理解成相反问题,比如原问题是求解最大值的线性规划,那么他的对偶问题就是转化为求解最小值的线性规划,适用于样本较小的数据集,因样本小时,计算复杂度较低。


tol:残差收敛条件,默认是0.0001,也就是只需要收敛的时候两步只差<0.0001就停止,可以设置更大或更小。(逻辑回归模型的损失函数是残差平方和)


C:正则化系数,正则化强度的导数,必须是一个正数,值越小,正则化强度越大,即防止过拟合的程度更大。


fit_intercept:是否将截距/方差加入到决策模型中,默认为True。


class_weight:class_weight是很重要的一个参数,是用来调节正负样本比例的,默认是值为None,也就是正负样本的权重是一样的,你可以以dict的形式给模型传入任意你认为合适的权重比,也可以直接指定一个值“balanced”,模型会根据正负样本的绝对数量比来设定模型最后结果的权重比。比如,有一数据集的正负样本绝对数量比为4:6,如果你给参数class_weight赋予balanced值,那么最后模型结果中,正负样本的权重比就会变成6:4。


random_state:随机种子的设置,默认是None,如果设置了随机种子,那么每次使用的训练集和测试集都是一样的,这样不管你运行多少次,最后的准确率都是一样的;如果没有设置,那么每次都是不同的训练集和测试集,最后得出的准确率也是不一样的。


solver:用来指明损失函数的优化方法,默认是‘liblinear’方法,sklearn自带了如下几种:

参数 说明
liblinear 使用了坐标轴下降法来迭代优化损失函数
lbfgs 拟牛顿法的一种,利用损失函数二阶导数矩阵(海森矩阵)来迭代优化损失函数
newton-cg 牛顿法的一种,利用损失函数二阶导数矩阵(海森矩阵)来迭代优化损失函数
sag 随机平均下降梯度,是梯度下降法的变种一种线性收敛算法,和一般的梯度下降算法的区别是每次迭代只使用部分样本计算梯度,使用于样本数据较多的时候

max_iter:算法收敛的最大迭代次数,即求取损失函数最小值的迭代次数,默认是100,


multi_class:分类方法参数选择,‘ovr’和‘multinomial’两个值可以选择,默认值为‘ovr’,如果分类问题是二分类问题,那么这两个参数的效果是一样的,主要体现在多分类问题上。对于多分类问题,"ovr"分类方法是:针对每一类别进行判断时,都会把这个分类问题简化为是/非两类问题;而‘multinomial’是从众多类别中选出两个类别,对这两个类别进行判断,待判断完成后,再从剩下的类别中再选出两类进行判断,直至最后判断完成。


verbose:英文意思是”冗余“,就是会输出一些模型运算过程中的东西(任务进程),默认是False,也就是不需要输出一些不重要的计算过程。


warm_start:是否使用上次的模型结果作为初始化,默认是False,表示不使用。


n_jobs:并行运算数量(核的数量),默认为1,如果设置为-1,则表示将电脑的cpu全部用上。


模型对象

coef_:返回各特征的系数,绝对值大小可以理解成特征重要性
intercept_:返回模型的截距
n_iter_:模型迭代次数


模型方法

decision_function(X):返回决策函数值(比如svm中的决策距离)
predict_proba(X):返回每个类别的概率值(有几类就返回几列值)
predict_log_proba(X):返回概率值的log值(即将概率取对数)
predict(X):返回预测结果值(0/1)
score(X, y=None):返回函数
get_params(deep=True):返回估计器的参数
set_params(**params):为估计器设置参数

  • 实例
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

path = '/Users/wcjb/Downloads/chapter5/demo/data/bankloan.xls'
bank = pd.read_excel(path)
  • 数据预处理

统计数据包含无效值(Nan,空值等)的个数

bank[bank.isnull().any(axis=1)].count()
年龄       0
教育       0
工龄       0
地址       0
收入       0
负债率      0
信用卡负债    0
其他负债     0
违约       0
dtype: int64

说明数据都是有效的

bank.describe()
sns.boxplot(bank['收入'])
bank[bank['收入']>100].count()
年龄       43
教育       43
工龄       43
地址       43
收入       43
负债率      43
信用卡负债    43
其他负债     43
违约       43
dtype: int64
sns.distplot(bank['收入'],bins=100)
bank['教育'].value_counts()
1    372
2    198
3     87
4     38
5      5
Name: 教育, dtype: int64
from sklearn.linear_model import LogisticRegression as LR
from sklearn.linear_model import RandomizedLogisticRegression as RLR
from sklearn.model_selection import train_test_split

x = bank.iloc[:,:8].values
y = bank.iloc[:,8].values
# 对原始数据集进行划分,0.7的训练集和0.3的测试集
xTrain,xTest,yTrain,yTest = train_test_split(x,y,test_size=0.3)
# 建立随机逻辑模型进行特征筛选
rlr = RLR()
rlr.fit(xTrain,yTrain)
RandomizedLogisticRegression(C=1, fit_intercept=True, memory=None,
               n_jobs=None, n_resampling=200, normalize=True,
               pre_dispatch='3*n_jobs', random_state=None,
               sample_fraction=0.75, scaling=0.5, selection_threshold=0.25,
               tol=0.001, verbose=False)
# 获取各个特征的分数
rlr.all_scores_
array([[0.035],
       [0.015],
       [0.6  ],
       [0.27 ],
       [0.   ],
       [0.945],
       [0.545],
       [0.065]])
# 获得特征筛选结果
rlr.get_support()
array([False, False,  True,  True, False,  True,  True, False])
print('有效特征为:%s'%','.join(bank.iloc[:,:8].columns[rlr.get_support()]))
有效特征为:工龄,地址,负债率,信用卡负债
  • 使用筛选出来的特征建立模型
x = bank[bank.columns[rir.get_support()]].value
model = LR()
model.fit(x,y)
LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,
          intercept_scaling=1, max_iter=100, multi_class='warn',
          n_jobs=None, penalty='l2', random_state=None, solver='warn',
          tol=0.0001, verbose=0, warm_start=False)
# 模型的拟合优度
model.score(x,y)
0.8057142857142857
# 模型参数
model.coef_
array([[ 0.02554555,  0.05665878, -0.25871395, -0.10043876, -0.00983243,
         0.05724028,  0.64150199,  0.08319484]])
# 模型的常量(截距)
model.intercept_
array([-1.13355153])
# 模型在测试集预测的正确率
count = 0
for i in (model.predict(xTest)-yTest):
    if i==0:
        count+=1
count/len(yTest)
0.8285714285714286

你可能感兴趣的:(Logistic模型及其Scikit-learn实现)