数据挖掘建模-Logistic回归

        逻辑回归的基本过程:a建立回归或者分类模型--->b 建立代价函数 ---> c 优化方法迭代求出最优的模型参数  --->d 验证求解模型的好坏。

1.逻辑回归模型:

 

逻辑回归(Logistic Regression):基于线性回归的分类算法。一般用于解决二分类问题。

线性回归模型如下:

 

逻辑回归思想是基于线性回归(Logistic  Regression是广义的线性回归模型),公式如下:

其中,

称为Sigmoid函数

由图可知:Sigmoid函数值域是在(0 , 1)之间,中间值为0.5 ,所以逻辑回归函数可以表示数据属于某一类别的概率:

h_θ(x)  ≥ 0.5,预测 y=1 类

h_θ(x) <  0.5,预测 y=0类

2.代价函数

代价函数是基于最大似然函数推导出来的。

将上式(1)可写成下面这个式子:

将式子乘一个(-1/m),使用梯度下降法求最优解 θ 参数

 

当x和y为多维时:

            

2.1 梯度下降法求解最小值

         求解函数的最优解(极大值和极小值),在数学中我们一般会对函数求导,然后让导数等于0,获得方程,然后通过解方程直接得到结果。但是在机器学习中,我们的函数常常是多维高阶的,得到导数为0的方程后很难直接求解(有些时候甚至不能求解),所以就需要通过其他方法来获得这个结果,而梯度下降就是其中一种。

对θ 参数进行更新:

α 为学习率

3.正则化:

(1)过拟合问题 

过拟合即是过分拟合了训练数据,使得模型的复杂度提高,但是泛化能力较差。

 

(2)正则化方法 :
正则化是结构风险最小化策略的实现,是在经验风险上加一个正则化项或惩罚项。

正则项可以取不同的形式,在回归问题中取平方损失,就是参数的L2范数,也可以取L1范数。取平方损失时,模型的损失函数变为:

 

 

lambda是正则项系数(λ): 


• 如果它的值很大,说明对模型的复杂度惩罚大,可能导致欠拟合; (使得J(θ) 最小化,当λ 值很大时,θ→0)

如:曲线为  z=θ_0+θ_1 x_1+θ_2 x_1^2+λθ_3 x_2^3      ---->       θ_3→0


• 如果它的值很小,说明比较注重对训练数据的拟合,在训练数据上的偏差会小,但是可能会导致过拟合。(保留更多的θ)

 正则化后的梯度下降算法θ的更新变为:

 

            

 

 

 

4.逻辑回归的优缺点:

优点:(1)速度快, 适合二分类问题

            (2)简单易于理解, 直接看到各个特征的权重

            (3)能容易吸收新的数据

缺点:对数据和场景的使用能力有限, 不如决策树算法适应性强

      ​  

 

对某一银行在降低贷款拖欠率的数据进行逻辑回归建模:

使用稳定性选择方法中的随机逻辑回归进行特征筛选, 然后对筛选后的特征建立逻辑回归模型

#coding=gbk
#使用稳定性选择方法中的随机逻辑回归进行特征筛选, 然后对筛选后的特征建立逻辑回归模型
import pandas as pd 
import numpy as np
filename = r'D:\datasets\bankloan.xls'
data = pd.read_excel(filename)
print(data.head())
#    年龄  教育  工龄  地址   收入   负债率      信用卡负债      其他负债  违约
# 0  41   3  17  12  176   9.3  11.359392  5.008608   1
# 1  27   1  10   6   31  17.3   1.362202  4.000798   0
# 2  40   1  15  14   55   5.5   0.856075  2.168925   0
# 3  41   1  15  14  120   2.9   2.658720  0.821280   0
# 4  24   2   2   0   28  17.3   1.787436  3.056564   1
x = data.iloc[:,:8].as_matrix()
y = data.iloc[:,8].as_matrix()      #转换成矩阵形式,使其没有索引项    是否违约1,0

from sklearn.linear_model import RandomizedLogisticRegression as RLR
rlr = RLR()
rlr.fit(x, y)
rlr.get_support()   #获取特征筛选结果, 
print(rlr.get_support())    #[False False  True  True False  True  True False]
print(rlr.scores_)  #[0.085 0.045 0.995 0.395 0.    0.995 0.595 0.04 ]        获取特征结果的分数
print('通过随机逻辑回归模型筛选特征结束')
# print(u'有效特征为:%s' % ','.join(data.columns[rlr.get_support()]))
# x = data[data.columns[rlr.get_support()]].as_matrix()
print(u'有效特征为:%s' % ','.join(np.array(data.iloc[:,:8].columns)[rlr.get_support()]))

x = data[np.array(data.iloc[:,:8].columns)[rlr.get_support()]].as_matrix() #筛选好特征

from sklearn.linear_model import LogisticRegression as LR
lr = LR()
lr.fit(x,y)
print('通过逻辑回归模型训练结束')
print('模型的平均正确率为: %s' % lr.score(x,y))
# 通过随机逻辑回归模型筛选特征结束
# 有效特征为:工龄,地址,负债率,信用卡负债
# 通过逻辑回归模型训练结束
# 模型的平均正确率为: 0.8142857142857143

矩阵形式的梯度下降方法:

\theta = \theta - \alpha X^T(h_{\theta}(X) - Y )

Python中逻辑回归的实现:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
__title__ = ''
__author__ = 'mike_jun'
__mtime__ = '2019-6-19'
#目的: 逻辑回归的实现
"""
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split

def create_data():
    iris = load_iris()
    df = pd.DataFrame(iris.data, columns=iris.feature_names)
    df['label'] = iris.target
    df.columns = ['sepal length', 'sepal width', 'petal length', 'petal width', 'label']
    data = np.array(df.iloc[:100, [0, 1, -1]]) #只是使用 2 个特征
    return data[:, :2], data[:, -1]

X, y = create_data()
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)
print(X_train.shape) # (70, 2)

class LogisticRegression():
    def __init__(self, learning_rate=0.05, max_iter=500, random_state=666):
        self.learning_rate = learning_rate
        self.max_iter = max_iter
        self.random_state = random_state
        self.theta = None
        self.inter_ = None
        self.weights = None

    def sigmoid(self, x, theta):
        # 返回经过sigmoid计算后的数字
        return 1 / (1 + np.exp(-np.dot(x, theta)))

    def leftAppend(self, x):
        # 在数组的最左边增加一列全是 1 的数字, 用作计算截距
        allOnes = np.ones(shape=(x.shape[0],  1))
        x = np.c_[allOnes, x]
        return x

    def fit(self, x, y):
        y = y.reshape(-1, 1) # 必须进行此步操作
        x = self.leftAppend(x)
        # 初始化theta
        # self.theta = np.zeros(shape=(x.shape[1], 1))
        # 正态分布初始化theta
        np.random.seed(self.random_state)
        self.theta = np.random.randn(x.shape[1], 1)
        print(self.theta.shape)

        # 进行梯度下降
        errors = []
        for iter_ in range(self.max_iter):
            h_x = self.sigmoid(x, self.theta)
            # print(h_x.shape)
            self.theta = self.theta - self.learning_rate * np.dot(x.T, (h_x - y))
            # 计算损失
            error = np.sum(h_x - y)
            errors.append(error)
        print(errors)
        return self

    def predict(self, X_test):
        # 对输入向量进行预测
        X_test = self.leftAppend(X_test)
        y_pred = self.sigmoid(X_test, self.theta)
        return y_pred

    def score(self, X_test, y_test):
        #获得测试集的得分
        X_test = self.leftAppend(X_test)
        y_test = y_test.reshape(-1, 1)
        # 将sigmoid 大于等于 0.5 的值预测为1, 反之则为0
        results = self.sigmoid(X_test, self.theta)
        results = np.where(results >= 0.5, 1, 0)
        counts = len(y_test)
        trueNum = np.sum(y_test == results)
        scores = trueNum / counts
        print(scores)
        return scores

    def printTheta(self):
        print(self.theta)
        self.inter_ = self.theta[0]
        self.weights = self.theta[1:]
        print('截距为:', self.inter_)
        print('权重值为:', self.weights)

lr = LogisticRegression()
lr.fit(X_train, y_train)
lr.printTheta()
lr.score(X_test, y_test)
# x = lr.leftAppend(X_train)
# print(x.shape)

# 画出全部数据
plt.scatter(X[:50, 0], X[:50, 1])
plt.scatter(X[50:, 0], X[50:, 1])
x_ponits = np.arange(4, 8)
# theta_1 * x + theta_2 * y + theta_0 = 0
# 根据公式画出决策边界
y_ = -(lr.theta[1]*x_ponits + lr.theta[0])/lr.theta[2]
plt.plot(x_ponits, y_)
plt.show()

 

 

sklearn 中 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='liblinear', max_iter=100, 
          multi_class='ovr', verbose=0, warm_start=False, n_jobs=1)

penalty='l2' : 字符串‘l1’或‘l2’,默认‘l2’。

  • 用来指定惩罚的基准(正则化参数)。只有‘l2’支持‘newton-cg’、‘sag’和‘lbfgs’这三种算法。
  • 如果选择‘l2’,solver参数可以选择‘liblinear’、‘newton-cg’、‘sag’和‘lbfgs’这四种算法;如果选择‘l1’的话就只能用‘liblinear’算法。
  •  在调参时如果我们主要的目的只是为了解决过拟合,一般penalty选择L2正则化就够了。但是如果选择L2正则化发现还是过拟合,即预测效果差的时候,就可以考虑L1正则化。另外,如果模型的特征非常多,我们希望一些不重要的特征系数归零,从而让模型系数稀疏化的话,也可以使用L1正则化。

dual=False : 对偶或者原始方法。Dual只适用于正则化相为l2的‘liblinear’的情况,通常样本数大于特征数的情况下,默认为False。C=1.0 : C为正则化系数λ的倒数,必须为正数,默认为1。和SVM中的C一样,值越小,代表正则化越强。fit_intercept=True : 是否存在截距,默认存在。intercept_scaling=1 : 仅在正则化项为‘liblinear’,且fit_intercept设置为True时有用。solver='liblinear' : solver参数决定了我们对逻辑回归损失函数的优化方法,有四种算法可以选择。

  • a) liblinear:使用了开源的liblinear库实现,内部使用了坐标轴下降法来迭代优化损失函数。
  • b) lbfgs:拟牛顿法的一种,利用损失函数二阶导数矩阵即海森矩阵来迭代优化损失函数。
  • c) newton-cg:也是牛顿法家族的一种,利用损失函数二阶导数矩阵即海森矩阵来迭代优化损失函数。
  • d) sag:即随机平均梯度下降,是梯度下降法的变种,和普通梯度下降法的区别是每次迭代仅仅用一部分的样本来计算梯度,适合于样本数据多的时候。

       sag每次仅仅使用了部分样本进行梯度迭代,所以当样本量少的时候不要选择它,而如果样本量非常大,比如大于10万,sag是第一选择。但是sag不能用于L1正则化,所以当你有大量的样本,又需要L1正则化的话就要自己做取舍了。要么通过对样本采样来降低样本量,要么回到L2正则化。

 

正则化算法适用场景
L1 liblinear liblinear适用于小数据集;如果选择L2正则化发现还是过拟合,即预测效果差的时候,就可以考虑L1正则化;如果模型的特征非常多,希望一些不重要的特征系数归零,从而让模型系数稀疏化的话,也可以使用L1正则化。
L2 liblinear libniear只支持多元逻辑回归的OvR,不支持MvM,但MVM相对精确。
L2 lbfgs/newton-cg/sag 较大数据集,支持one-vs-rest(OvR)和many-vs-many(MvM)两种多元逻辑回归。
L2 sag 如果样本量非常大,比如大于10万,sag是第一选择;但不能用于L1正则化。

multi_class='ovr' : 分类方式。官网有个对比两种分类方式的例子:链接地址

  • ovr即one-vs-rest(OvR),multinomial是many-vs-many(MvM)。如果是二元逻辑回归,ovr和multinomial并没有任何区别,区别主要在多元逻辑回归上。
  • ovr不论是几元回归,都当成二元回归来处理。mvm从从多个类中每次选两个类进行二元回归。如果总共有T类,需要T(T-1)/2次分类。
  • OvR相对简单,但分类效果相对略差(大多数样本分布情况)。而MvM分类相对精确,但是分类速度没有OvR快。
  • 如果选择了ovr,则4种损失函数的优化方法liblinear,newton-cg,lbfgs和sag都可以选择。但是如果选择了multinomial,则只能选择newton-cg, lbfgs和sag了。

class_weight=None : 类型权重参数。用于标示分类模型中各种类型的权重。默认不输入,即所有的分类的权重一样。

  • 选择‘balanced’自动根据y值计算类型权重。
  • 自己设置权重,格式:{class_label: weight}。例如0,1分类的er'yuan二元模型,设置class_weight={0:0.9, 1:0.1},这样类型0的权重为90%,而类型1的权重为10%。

random_state=None : 随机数种子,默认为无。仅在正则化优化算法为sag,liblinear时有用。

max_iter=100 : 算法收敛的最大迭代次数。

tol=0.0001 : 迭代终止判据的误差范围。

verbose=0 : 日志冗长度int:冗长度;0:不输出训练过程;1:偶尔输出; >1:对每个子模型都输出

warm_start=False : 是否热启动,如果是,则下一次训练是以追加树的形式进行(重新使用上一次的调用作为初始化)。布尔型,默认False。

n_jobs=1 : 并行数,int:个数;-1:跟CPU核数一致;1:默认值。

 

LogisticRegression类的常用方法

  • fit(X, y, sample_weight=None)
    • 拟合模型,用来训练LR分类器,其中X是训练样本,y是对应的标记向量
    • 返回对象,self。
  • fit_transform(X, y=None, **fit_params)
    • fit与transform的结合,先fit后transform。返回X_new:numpy矩阵。
  • predict(X)
    • 用来预测样本,也就是分类,X是测试集。返回array。
  • predict_proba(X)
    • 输出分类概率。返回每种类别的概率,按照分类类别顺序给出。如果是多分类问题,multi_class="multinomial",则会给出样本对于每种类别的概率。
    • 返回array-like。
  • score(X, y, sample_weight=None)
    • 返回给定测试集合的平均准确率(mean accuracy),浮点型数值。
    • 对于多个分类返回,则返回每个类别的准确率组成的哈希矩阵。


使用逻辑回归解决多分类问题:

直接使用 LogisticRegression  和 使用 multiclass 

#coding=gbk
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split 
from sklearn.datasets import load_iris 
iris = load_iris()
print(iris.data.shape)  #有4个分类
print(iris.target.shape)    # (150, 4)
print(iris.data[:5, :])
X = iris.data 
y = iris.target 
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=666)

lr_iris_ovr = LogisticRegression()  #默认使用 'ovr' 进行多分类
lr_iris_ovr.fit(X_train, y_train)
print(lr_iris_ovr.score(X_test, y_test))    # 0.9111111111111111

lr_iris_ovo = LogisticRegression(multi_class='multinomial', solver='newton-cg') #使用'ovo'进行多分类
lr_iris_ovo.fit(X_train, y_train)
print(lr_iris_ovo.score(X_test, y_test)) # 1.0

#使用另一种方法解决多分类问题
from sklearn.multiclass import OneVsOneClassifier #  'ovo' 分类
from sklearn.multiclass import OneVsRestClassifier
ovr = OneVsRestClassifier(lr_iris_ovr)
ovr.fit(X_train, y_train)
print(ovr.score(X_test, y_test))    # 0.9111111111111111 得到的数据是与上述的使用 ovr 的结果一样

ovo = OneVsOneClassifier(lr_iris_ovo)   #传入分类器的参数
ovo.fit(X_train, y_train)
print(ovo.score(X_test, y_test))    # 1.0



参考:机器学习之逻辑回归

           刘建平的blog


 

posted @ 2020-04-23 15:19  蜘蛛侠不会飞  阅读(874)  评论(0编辑  收藏  举报

俺的博客

https://blog.csdn.net/qq_40587575

俺的公众号