首页 > 编程语言 > 详细

A--利用梯度下降求解逻辑回归的python实现

时间:2019-11-22 09:08:15      阅读:97      评论:0      收藏:0      [点我收藏+]
#导入必要的包
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.

 
 
 

A--利用梯度下降求解逻辑回归的python实现

原文:https://www.cnblogs.com/Koi504330/p/11909398.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!