zoukankan      html  css  js  c++  java
  • A--利用梯度下降求解逻辑回归的python实现

    #导入必要的包
    import numpy as np
    import pandas as pd
    import matplotlib as mpl
    import matplotlib.pyplot as plt
    %matplotlib inline

    BGD求解逻辑回归

    In [2]:
    #⾸先定义联系函数sigmoid函数
    def sigmoid(inX):
        return 1.0/(1+np.exp(-inX))

    In [7]:

    #自定义一个归一化函数(此函数的前提是我的数据是一个矩阵)
    def regularize(xMat):
        inMat = xMat.copy()#创建一个副本,这样对inmat进行操作不会影响到xmat
        inMeans = np.mean(inMat,axis = 0) #求均值
        inVar = np.std(inMat,axis = 0) #求标准差
        inMat = (inMat - inMeans)/inVar #归一化
        return inMat
    In [4]:
    #编写批量梯度下降的自定义函数
    def logisticReg_0(dataSet,eps=0.01,numIt=50000):
        xMat = np.mat(dataSet.iloc[:, :-1].values)
        yMat = np.mat(dataSet.iloc[:, -1].values).T
        xMat = regularize(xMat)
        m,n = xMat.shape
        weights = np.zeros((n,1))
        for k in range(numIt): 
            grad = xMat.T * (sigmoid(xMat * weights) - yMat) / m#加入了sigmoid函数
            weights = weights - eps * grad
        return weights
     
    In [37]:
    testSet = pd.read_table('testSet.txt', header=None)
    testSet.head()#一个二分类数据集
    Out[37]:
     012
    0 -0.017612 14.053064 0
    1 -1.395634 4.662541 1
    2 -0.752157 6.538620 0
    3 -1.322371 7.152853 0
    4 0.423363 11.054677 0
    In [12]:
    ws = logisticReg_0(testSet, eps=0.01,numIt=500)
    ws
    Out[12]:
    matrix([[ 0.08644437],
            [-1.26921488]])
     

    计算准确率

    In [13]:
    #提取Xmat与Ymat
    xMat = np.mat(testSet.iloc[:, :-1].values)
    yMat = np.mat(testSet.iloc[:, -1].values).T
    xMat = regularize(xMat)#对xmat归一化,ymat本身就是o和1 所以不用归一化了
     
    In [14]:
    (xMat * ws).A.flatten()#求得方程本身并转换成array再转换成行向量
    Out[14]:
    array([-2.05688038,  0.41967771, -0.04776864, -0.25878106, -1.20071802,
           -0.1069381 , -1.64582994, -0.26468857, -0.77631505, -1.06195274,
           -0.03362803, -1.71456551,  1.02134785, -0.82706158,  0.18285287,
            1.4363693 ,  0.11249424,  1.06201058,  1.66712589,  0.29874123,
            1.06389991,  1.83112447, -1.4738391 ,  2.23899711,  0.91209097,
           -0.74142665, -0.7494692 ,  1.97772498,  0.85942228, -0.73277762,
            0.67949527, -0.43292764, -1.28750584,  2.36442777,  0.53266104,
           -0.79675144, -0.72426019, -0.95718379, -1.64652946, -1.39006337,
            0.86512364,  0.20447648, -1.07659337,  1.73862742,  1.13032652,
           -1.1851674 ,  2.34784817,  0.1944565 , -1.4408959 , -1.17870617,
           -0.57766565, -1.05843461, -0.43883063, -1.90571443,  0.53484842,
           -0.06615649, -1.165083  , -0.18341635, -1.43918646,  0.47298352,
            0.61004349,  1.30172164, -0.68923266, -1.58831196, -1.54353632,
            2.14613556,  0.21291662, -1.2877214 , -1.46745076, -1.27794798,
           -1.21807298,  1.57582052, -1.98372337,  1.00328841, -0.87300219,
           -0.20031198,  1.68812137,  1.30544075,  0.57776419,  0.53883724,
            0.02686256,  2.59762059, -0.8853089 , -0.2801372 ,  1.25846702,
            2.21790839,  0.68382909, -1.56049535,  0.43216125,  1.79315117,
            2.00679837, -1.54676186, -0.85772193,  1.55979868,  1.41807387,
            1.15193462, -1.07653949,  1.60327969, -0.65872133, -2.22041914])
    In [15]:
    #进⼀步乘以sigmoid函数之后得到的是y取得1的概率⼤⼩
    p = sigmoid(xMat * ws).A.flatten()
    p
     
    Out[15]:
    array([0.113359  , 0.60340613, 0.48806011, 0.43566337, 0.23134751,
           0.47329092, 0.16167334, 0.4342115 , 0.31511462, 0.25693646,
           0.49159379, 0.15257249, 0.73523506, 0.30426674, 0.54558627,
           0.80789179, 0.52809394, 0.74307458, 0.84119225, 0.57413477,
           0.74343512, 0.86189563, 0.18635979, 0.90369721, 0.71342785,
           0.32269225, 0.32093697, 0.87843843, 0.70253994, 0.32458549,
           0.66362604, 0.39342746, 0.21627527, 0.91407421, 0.63010354,
           0.31072085, 0.32645555, 0.2774424 , 0.16157856, 0.19939764,
           0.70373002, 0.55094175, 0.25415123, 0.85051264, 0.75589915,
           0.23412436, 0.91276304, 0.54846151, 0.19140665, 0.23528491,
           0.3594699 , 0.25760872, 0.39201964, 0.12946308, 0.63061322,
           0.48346691, 0.23774491, 0.45427403, 0.19167136, 0.61608967,
           0.64795072, 0.78612459, 0.33420379, 0.16962153, 0.17602179,
           0.89530711, 0.55302897, 0.21623874, 0.18733039, 0.21789973,
           0.22827575, 0.82861179, 0.12092248, 0.73170463, 0.29462999,
           0.45008878, 0.84397694, 0.78674923, 0.64055278, 0.63154189,
           0.50671524, 0.93070829, 0.29207885, 0.43042014, 0.7787621 ,
           0.9018462 , 0.66459277, 0.17357558, 0.60638964, 0.85731319,
           0.88150902, 0.17555445, 0.29781552, 0.82632446, 0.80503628,
           0.75986411, 0.25416144, 0.83247627, 0.3410269 , 0.09793177])
     

    enumerate(p) 函数:返回一个索引和值组成二元可迭代对象

    In [16]:
     
    #我们可令p>0.5时预测输出值为1,反之为0,得到最终y值预测结果
    for i, j in enumerate(p):
        if j < 0.5: 
            p[i] = 0
        else:
            p[i] = 1
    In [17]:
    p
    Out[17]:
    array([0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 1., 1., 1.,
           1., 1., 1., 1., 1., 0., 1., 1., 0., 0., 1., 1., 0., 1., 0., 0., 1.,
           1., 0., 0., 0., 0., 0., 1., 1., 0., 1., 1., 0., 1., 1., 0., 0., 0.,
           0., 0., 0., 1., 0., 0., 0., 0., 1., 1., 1., 0., 0., 0., 1., 1., 0.,
           0., 0., 0., 1., 0., 1., 0., 0., 1., 1., 1., 1., 1., 1., 0., 0., 1.,
           1., 1., 0., 1., 1., 1., 0., 0., 1., 1., 1., 0., 1., 0., 0.])
    In [18]:
    testSet[3]=p
    testSet

     . .

    In [19]:
    #首先封装一个准确率判断模型
    def accuracyCalculation(dataSet):
        m = dataSet.shape[0]
        #如果后一列数据=前一列数据,对返回为True的行计数
        res = (dataSet.iloc[:, -1] == dataSet.iloc[:, -2]).value_counts()
        acc = res.loc[True] / m
        print("Model accuracy is :{}".format(acc) )
        return acc
     
    In [20]:
    accuracyCalculation(testSet) #准确率%92
    Model accuracy is :0.92
    
    Out[20]:
    0.92
    In [21]:
    train_error = (np.fabs(yMat.A.flatten() - p)).sum()
    train_error  #判断错误个数又8个
    Out[21]:
    8.0
    In [22]:
    train_error_rate = train_error / yMat.shape[0]
    train_error_rate  #相对的 错误率为8
    Out[22]:
    0.08
    In [24]:
    #参数分别为  数据集   模型  学习率   迭代次数
    def logisticAcc(dataSet, method, eps=0.01, numIt=50000):
        weights = method(dataSet,eps=eps,numIt=numIt) 
        p = sigmoid(xMat * ws).A.flatten()
        for i, j in enumerate(p):
            if j < 0.5: 
                p[i] = 0
            else:p[i] = 1
        train_error = (np.fabs(yMat.A.flatten() - p)).sum()
        trainAcc = 1 - train_error / yMat.shape[0]
        return trainAcc
     
    In [26]:
    import time
    %time logisticAcc(testSet,logisticReg_0)
    Wall time: 6 s
    
    Out[26]:
    0.92
     

    SGD求解逻辑回归

    In [32]:
    def logisticReg_1(dataSet,eps=0.01,numIt=50000):
        dataSet = dataSet.sample(numIt, replace=True)
        dataSet.index = range(dataSet.shape[0])
        xMat = np.mat(dataSet.iloc[:, :-1].values)
        yMat = np.mat(dataSet.iloc[:, -1].values).T
        xMat = regularize(xMat) 
        m,n = xMat.shape
        weights = np.zeros((n,1))
        for i in range(m): 
            grad = xMat[i].T * (sigmoid(xMat[i] * weights) - yMat[i])
            weights = weights - eps * grad
        return weights
    In [38]:
    logisticReg_1(testSet)

    Out[38]:

    matrix([[ 1.31302158],
            [-6.52145044]])
    In [39]:
    %time logisticAcc(testSet,logisticReg_1)
    Wall time: 7.46 s
    
    Out[39]:
    0.92
    逻辑回归的Scikit-Learn实现
    In [40]:
    from sklearn.linear_model import LogisticRegression
    clf = LogisticRegression()
    clf.fit(testSet.iloc[:, :-1], testSet.iloc[:, -1])

    Out[40]:

    LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,
              intercept_scaling=1, max_iter=100, multi_class='ovr', n_jobs=1,
              penalty='l2', random_state=None, solver='liblinear', tol=0.0001,
              verbose=0, warm_start=False)
    In [41]:
    clf.coef_
    Out[41]:
    array([[ 0.44732445, -0.58003724]])
    In [42]:
    clf.intercept_
    Out[42]:
    array([3.83513265])
    In [43]:
    clf.predict(testSet.iloc[:, :-1])
    Out[43]:
    array([0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1,
           0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1,
           1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1,
           1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0,
           1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0], dtype=int64)
    In [44]:
    from sklearn.metrics import accuracy_score
    accuracy_score(testSet.iloc[:, -1], clf.predict(testSet.iloc[:, :-1]))
    Out[44]:
    0.96
     

    注:梯度下降不适合求解回归方程,因为方程系数对线性回归是很重要的,我们可以根据系数直观的连接线性回归

    1.参数讲解

     

    1.1 概述

     

    在scikit-learn中,与逻辑回归有关的常用的有2类。

    LogisticRegression, LogisticRegressionCV,其中LogisticRegression和LogisticRegressionCV的主要区别是 LogisticRegressionCV使⽤了交叉验证来选择正则化系数C。⽽LogisticRegression需要⾃⼰每次指定 ⼀个正则化系数。除了交叉验证,以及选择正则化系数C以外, LogisticRegression和LogisticRegressionCV的使⽤⽅法基本相同。

     

    1.2 参数详解

     

    正则化参数penalty

     

    LogisticRegression和LogisticRegressionCV默认就带了正则化项。penalty参数可选择的值

    为"I1"和"I2".分别对应L1的正则化和L2的正则化,默认是L2的正则化。 在调参时如果我们主要的⽬的只是为了解决过拟合,⼀般penalty选择L2正则化就够了。但是如 果选择L2正则化发现还是过拟合,即预测效果差的时候,就可以考虑L1正则化。另外,如果模型 的特征⾮常多,我们希望⼀些不重要的特征系数归零,从⽽让模型系数稀疏化的话,也可以使⽤ L1正则化。 penalty参数的选择会影响我们损失函数优化算法的选择。即参数solver的选择,如果是L2正则 化,那么4种可选的算法{‘newton-cg’, ‘lbfgs’, ‘liblinear’, ‘sag’}都可以选择。但是如果penalty是L1 正则化的话,就只能选择‘liblinear’了。这是因为L1正则化的损失函数不是连续可导的,⽽ {‘newton-cg’, ‘lbfgs’,‘sag’}这三种优化算法时都需要损失函数的⼀阶或者⼆阶连续导数。 ⽽‘liblinear’并没有这个依赖。

     

    算法优化参数solver

     

    solver参数决定了我们对逻辑回归损失函数的优化⽅法,有4种算法可以选择,

    分别是: liblinear:使⽤了开源的liblinear库实现,内部使⽤了坐标轴下降法来迭代优化损失函数。 lbfgs:拟⽜顿法的⼀种,利⽤损失函数⼆阶导数矩阵即海森矩阵来迭代优化损失函数。 newton-cg:也是⽜顿法家族的⼀种,利⽤损失函数⼆阶导数矩阵即海森矩阵来迭代优化损失函 数。 sag:即随机平均梯度下降,是梯度下降法的变种,和普通梯度下降法的区别是每次迭代仅仅⽤ ⼀部分的样本来计算梯度,适合于样本数据多的时候。 从上⾯的描述可以看出,newton-cg, lbfgs和sag这三种优化算法时都需要损失函数的⼀阶或者 ⼆阶连续导数,因此不能⽤于没有连续导数的L1正则化,只能⽤于L2正则化。⽽liblinear通吃L1 正则化和L2正则化。 同时,sag每次仅仅使⽤了部分样本进⾏梯度迭代,所以当样本量少的时候不要选择它,⽽如果 样本量⾮常⼤,⽐如⼤于10万,sag是第⼀选择。但是sag不能⽤于L1正则化,所以当你有⼤量 的样本,⼜需要L1正则化的话就要⾃⼰做取舍了。要么通过对样本采样来降低样本量,要么回到 L2正则化。 从上⾯的描述,⼤家可能觉得,既然newton-cg, lbfgs和sag这么多限制,如果不是⼤样本,我们 选择liblinear不就⾏了嘛!错,因为liblinear也有⾃⼰的弱点!我们知道,逻辑回归有⼆元逻辑 回归和多元逻辑回归。对于多元逻辑回归常⻅的有one-vs-rest(OvR)和many-vs-many(MvM)两 种。⽽MvM⼀般⽐OvR分类相对准确⼀些。郁闷的是liblinear只⽀持OvR,不⽀持MvM,这样如 果我们需要相对精确的多元逻辑回归时,就不能选择liblinear了。也意味着如果我们需要相对精 确的多元逻辑回归不能使⽤L1正则化了。

     

    分类⽅式选择参数

     

    multi_class参数决定了我们分类⽅式的选择,有 ovr和multinomial两个值可以选择,默认是 ovr。

    ovr即前⾯提到的one-vs-rest(OvR),⽽multinomial即前⾯提到的many-vs-many(MvM)。如果 是⼆元逻辑回归,ovr和multinomial并没有任何区别,区别主要在多元逻辑回归上。 OvR的思想很简单,⽆论你是多少元逻辑回归,我们都可以看做⼆元逻辑回归。具体做法是,对 于第K类的分类决策,我们把所有第K类的样本作为正例,除了第K类样本以外的所有样本都作为 负例,然后在上⾯做⼆元逻辑回归,得到第K类的分类模型。其他类的分类模型获得以此类推。 ⽽MvM则相对复杂,这⾥举MvM的特例one-vs-one(OvO)作讲解。如果模型有T类,我们每次在 所有的T类样本⾥⾯选择两类样本出来,不妨记为T1类和T2类,把所有的输出为T1和T2的样本放 在⼀起,把T1作为正例,T2作为负例,进⾏⼆元逻辑回归,得到模型参数。我们⼀共需要T(T- 1)/2次分类。 从上⾯的描述可以看出OvR相对简单,但分类效果相对略差(这⾥指⼤多数样本分布情况,某些 样本分布下OvR可能更好)。⽽MvM分类相对精确,但是分类速度没有OvR快。 如果选择了ovr,则4种损失函数的优化⽅法liblinear,newton-cg, lbfgs和sag都可以选择。但是 如果选择了multinomial,则只能选择newton-cg, lbfgs和sag了。

     

    分类权重参数

     

    class_weight参数⽤于标示分类模型中各种类型的权重,

    可以不输⼊,即不考虑权重,或者说所 有类型的权重⼀样。如果选择输⼊的话,可以选择balanced让类库⾃⼰计算类型权重,或者我 们⾃⼰输⼊各个类型的权重,⽐如对于0,1的⼆元模型,我们可以定义class_weight={0:0.9, 1:0.1},这样类型0的权重为90%,⽽类型1的权重为10%。 如果class_weight选择balanced,那么类库会根据训练样本量来计算权重。某种类型样本量越 多,则权重越低,样本量越少,则权重越⾼。 那么class_weight有什么作⽤呢?在分类模型中,我们经常会遇到两类问题: 第⼀种是误分类的代价很⾼。⽐如对合法⽤户和⾮法⽤户进⾏分类,将⾮法⽤户分类为合法⽤户 的代价很⾼,我们宁愿将合法⽤户分类为⾮法⽤户,这时可以⼈⼯再甄别,但是却不愿将⾮法⽤ 户分类为合法⽤户。这时,我们可以适当提⾼⾮法⽤户的权重。 第⼆种是样本是⾼度失衡的,⽐如我们有合法⽤户和⾮法⽤户的⼆元样本数据10000条,⾥⾯合 法⽤户有9995条,⾮法⽤户只有5条,如果我们不考虑权重,则我们可以将所有的测试集都预测 为合法⽤户,这样预测准确率理论上有99.95%,但是却没有任何意义。这时,我们可以选择 balanced,让类库⾃动提⾼⾮法⽤户样本的权重。 提⾼了某种分类的权重,相⽐不考虑权重,会有更多的样本分类划分到⾼权重的类别,从⽽可以 解决上⾯两类问题。

     

    样本权重参数

     

    之前我们提到了样本不失衡的问题,由于样本不平衡,导致样本不是总体样本的⽆偏估计.

    从⽽ 可能导致我们的模型预测能⼒下降。遇到这种情况,我们可以通过调节样本权重来尝试解决这个 问题。调节样本权重的⽅法有两种,第⼀种是在class_weight使⽤balanced。第⼆种是在调⽤fit 函数时,通过sample_weight来⾃⼰调节每个样本权重。 在scikit-learn做逻辑回归时,如果上 ⾯两种⽅法都⽤到了,那么样本的真正权重是class_weight*sample_weight.

     
     
     
  • 相关阅读:
    中断高深吗?不!和我一起了解它!(三)
    IIS7下uploadify上传大文件出现404错误
    初来博客园
    cxf3.x +spring 3.x(4.x)+ maven 发布webservice 服务
    angularjs + fis +modJS 对于支持amd规范的组建处理(PhotoSwipe 支持,百度webUpload支持)
    elasticsearch suggest 的几种使用completion 的基本 使用
    使用github+sublime+markdwon 写文章,写博客并发布到博客园
    小互联网公司
    linux pts
    linux添加用户例如oracle
  • 原文地址:https://www.cnblogs.com/Koi504330/p/11909398.html
Copyright © 2011-2022 走看看