线性模型Logistic_ 机器学习

前言

     logistic 回归也是一种简单的分类算法。

    主要应用在数据挖掘,模式识别领域。例如死亡率预测,广告点击次数预估,疾病诊断。

    优点:可解释性强,速度快


目录

  1.       Logistic 回归
  2.       算法推导
  3.      算法流程
  4.      L2 正规化
  5.      应用例子

一   Logistic 回归(梯度下降法)

     1.1 函数定义:

            h(z)=\frac{1}{1+e^{-Z}}

           其中

          Z=w^Tx  ,

          x=[1,...,x_n]^T   n维的列向量

         w=[w_0,w_1,..w_n]^T  权重向量

      

        

 

  

 

             这是一个单调递增函数,

             正样本概率为p(y=1|x)=h(x)>0.5

             负样本概率为p(y=0|x)=1-h(x)<0.5

 

1.2 函数解释:

              ln \frac{p(y=1|x)}{p(y=0|x)}

               =ln\frac{1/(1+e^{-Z})}{1- 1/(1+e^{-Z})}

               =Z= w^Tx, 正样本

 

   

  正样本概率大于负样本概率,则w^Tx>0


二  算法推导

    2.1   给定训练样本:

          (x_i, y_i),i=1,...,m 

         x_i 为n维特征向量

         y_i  为类别标签,y\in[0,1]

 

   定义似然函数,求解极大值: 

    L(w)= \prod_{i=1}^{m}(h(x_i))^{y_i}(1-h(x_i))^{1-y_i}

 

 取对数,等同 求解 对应n重伯努利分布 极小值

f(w)=-lnL(w)=-\sum_{i=1}^{m}y_i lnh(x_i) + (1-y_i)ln(1-h(x_i))

      

 

2.2  为了找到全局最小值,需要证明该函数是凸函数, 证明如下:

     因为其中y_i 为离散值, 分两种情况讨论:

   2.2.1  对任意某个样本 y_i=0 ,对w

          求一阶导数:

           =h(x_i)x_i

          二阶导数

        =h(x_i)(1-h(x_i))X

        X= [x_1^Tx_1,x_2^Tx_2,...x_m^Tx_m]^T

          =x_ix_i^T

       其中单个样本的特征向量为:

        x_i=[x_{i1},x_{i2},..,x_{in}]^T

      对于任意向量

       x^TXx= x^Tx_i (x_i^Tx)\geq 0

     所以Hessian矩阵大于0,是凸函数

   

  2.2. 2 y_i=1

       求一阶导数

      =-(1-h(x_i))x_i

 

       二阶导数为:

     =h(x_i)(1-h(x_i))X

      也是半正定的矩阵,所以

   -(y_i ln h(x_i)+ (1-y_i)ln(1-h(x_i)))

   也是凸函数

 

  合并上面的梯度,使用梯度下降法,求解极小值, 目标函数梯度:

    =\sum(h(x_i)-y_i)x_i

 

权重更新公式为

   w_{k+1}=w_k-\alpha \sum_{i=1}^{m}(h_w(x_i)-y_i)x_i

   


三 算法流程

      1: 计算当前的损失

             loss = h_w(x_i)-y_i

      2:   更新权重系数向量

          w_{k+1}=w_k-\alpha \sum_{i=1}^{m}(h_w(x_i)-y_i)x_i

      3:当前的迭代次数是否大于设置的迭代次数,

  ,或者梯度小于固定的值(梯度为0,就是全局最小值), 就停止迭代,否则

       重复1,2两步

      例子中w ,计算结果为

      Z=11.235x_1+1.009x_2-1.536x_3

 

 

四  L2 正规化(牛顿迭代法)

      L2正规化主要为了解决过拟合。

      3.1    对数似然函数:

           这里y \in [-1,1], 跟之前的不一样,依然是二分类

          

          可以得到似然函数为:

          L(w,b)=\prod_{i=1}^{m}\frac{1}{1+e^{-y_i(w^Tx_i+b)}}

         对数似然函数为:

          lnL(w,b)=-\sum_{i=1}^{m}(1+e^{-y_i(w^Tx+b)})

         等同求下面极小值

         f(w,b)=\sum ln(1+e^{-y_i(w^Tx_i+b)})

 

      3.2   正规化问题

             min_w f(w)=\frac{1}{2}w^Tw+C\sum ln(1+e^{-y_i(w^Tx_i)})

 

            该函数是两个凸函数的线性组合,依然是凸函数

            \bigtriangledown ln(1+e^{-y_iw^Tx_i})=-y_i(1-\frac{1}{1+e^{-y_iw^Tx_i}})x_i

            Hessian 矩阵为,二阶导数:

               >0

 

          则目标函数的梯度

          \bigtriangledown f(w) =w+C\sum_{i=1}^{m}(Sigmoid(y_iw^Tx_i)-1)y_ix_i

 

         其中:

         Sigmod(z)= \frac{1}{1+e^{-z}}

 

       Hessian 矩阵为:

        =I+C X^TDX

       其中

       X=[x_1,x_2,...,x_m]^T

      D 为对角矩阵,对角元素为:

      D_{ii}=Sigmoid(y_iw^Tx_i)(1-Sigmoid(y_iw^Tx_i))

 

      3.3 牛顿法迭代公式:

           w^{k+1}=w^{k}+s^k

 

        其中

    

      \triangledown^2f(w^k)s^k=-\triangledown f(w^k)

     s^k=-(\triangledown^2f(w^k))^{-1} \triangledown f(w^k)

 

     证明:

       泰勒公式展开损失函数

         f(w^{k+1})=f(w^k)+f'(w^k)(w^{k+1}-w^k)+\frac{f''(w^{k})(w^{k+1}-w^k)^2}{2}

          其中, w^k 是当前的权重系数,为已知值

      w^{k+1} 为下一轮迭代参数,未知值,我们求解的目标是凸函数,那下轮只要一阶导数为0,就可以达到极小值

     对 w^{k+1} 求导:

      0=f'(w^{k+1})=f'(w^k)+f''(w^k)(w^{k+1}-w^k)

     

     w^{k+1}=w^k-f"(w^k)^{-1}f(w^k)

     多维就换成梯度符号\triangledown

       

   算法流程:

       1: 计算梯度

              \bigtriangledown f(w) =w+C\sum_{i=1}^{m}(Sigmoid(y_iw^Tx_i)-1)y_ix_i

     2:  计算Hessian矩阵

            =I+C X^TDX

           其中D 为对角矩阵,I 单位矩阵(n*n) n为样本维度

          D_{ii}=Sigmoid(y_iw^Tx_i)(1-Sigmoid(y_iw^Tx_i))

 

     3: 计算迭代公式

         w^{k+1}=w^{k}+s^k

        其中:

       s^k=-(\triangledown^2f(w^k))^{-1} \triangledown f(w^k)

       前半部分为Hessian 矩阵的逆矩阵

    

 

 

牛顿法最大的问题在于我们必须计算海森矩阵的逆。注意在机器学习应用中,屏幕快照 2016-08-11 下午8.13.06.png的输入的维度常常与模型参数对应。十万维度的参数并不少见(SVM中文文本分类取词做特征的话,就在十万这个量级),在一些图像识别的场景中,参数可能上十亿。所以,计算海森矩阵或其逆并不现实。对许多函数而言,海森矩阵可能根本无法计算,更不用说表示出来求逆了。

所以,在实际应用中牛顿法很少用于大型的优化问题。但幸运的是,即便我们不求出屏幕快照 2016-08-11 下午8.13.06.png屏幕快照 2016-08-11 下午8.10.12.png的精确屏幕快照 2016-08-12 下午8.38.44.png,而使用一个近似的替代值,上述算法依然有效

 

         

           缺点:

        梯度下降法

                  收敛速度慢,可能会面临局部极小值

        牛顿迭代法

                  收敛速度快,维度过高时候  Hessian矩阵求逆计算量太大


         

五 例子:

    

# -*- coding: utf-8 -*-
"""
Created on Thu Oct 24 14:45:33 2019

@author: chengxf2
"""

import numpy as np

import matplotlib.pyplot as plt
import os
from sklearn.preprocessing import StandardScaler
from sklearn.datasets import load_breast_cancer



class MyLogistic:
    
    """
    绘制散点
    Draw2D
    Args
       data:
       color
    return
       None
    """
    def Draw2D(self, data, color):
        m,n = np.shape(data)
        
        x = np.array(data[:,n-2])
        y = np.array(data[:,n-1])
        
        
        plt.scatter(x.flatten(),  y.flatten(),c=color, cmap=plt.cm.cool)
        plt.xlabel("$z_1$", fontsize=18)
        plt.ylabel("$z_2$", fontsize=18)
        plt.show()
        
    
    """
    加载数据集
    Args
        None
    return
        Noe
    """
    def LoadData(self):
        
        path = os.path.abspath(self.fileName)
        fr = open(path)
        items = fr.readlines()
       
        trainData =[]
        trainLabel =[]
        for item in items:
            line = item.strip().split()
            para = [1.0, float(line[0]), float(line[1])]
            trainData.append(para)
            trainLabel.append(int(line[2]))
        
        self.m , self.n = np.shape(trainData)
        
        sc = StandardScaler()
        data = sc.fit_transform(trainData)
        
        self.trainData = np.mat(data)
        self.trainLabel = np.mat(trainLabel).T
        
        
        self.trainData[:,0]=1.0
        
        print("\n np.shape ", np.shape(self.trainLabel)) ##100,1
        
       
 

        
    
    """
    使用sigMode 预测
    Args
       Z: W*X
    return
       h: 预测值
    """
    def Sigmod(self, Z):
        
        a = 1.0/(1+np.exp(-Z))
        
        return a
    
    def __init__(self):
        
        self.m = 0  #样本的个数
        self.n = 0  #样本的维度
        self.maxIter = 3000
        self.minError = 1e-10 ##最低错误率
        self.fileName = "testSet.txt"
        self.alpha = 0.1
        self.LoadData()
        self.W = None
        
        
        
    """
    训练
    Args
       None
    return
       W
    """
    def Train(self):
        
        W = np.ones((self.n, 1))
        
      
        
        ParaW = []
        gradList = []
        
        print("\n self.trainData",self.trainData[0:3])
        for it in range(self.maxIter): 
            
          
            
            Z = self.trainData*W ##(100,1)
            
            A = self.Sigmod(Z) - self.trainLabel ##

            ##计算当前的梯度
            gradient =np.multiply(A, self.trainData)
            grad = np.sum(gradient, axis=0)
            #print("\n sp " ,grad)
            #lossT.append(np.sum(np.abs(loss)))
            err = np.linalg.norm(grad)
                
            if err<self.minError:
                break
           
            
            gradList.append(err)   
            W = W - (grad*self.alpha).T
            #W = W - self.trainData.T*loss*self.alpha  ##相当于取平均损失,批量梯度
            ParaW.append(W)
            
            
        
        print("\n self.w: \n",W)
        self.W = W
      
        
      
        
        t = np.arange(0,len(gradList),1.0)
        
        plt.figure()
        
        w1 = np.array(ParaW)[:,0].flatten()
        w2 = np.array(ParaW)[:,1].flatten()
        w3 = np.array(ParaW)[:,2].flatten()
        
        plt.subplot(221)
        plt.title("w1")
        plt.scatter(t, w1,c='r')
        
        
        
        plt.subplot(222)
        plt.title("w2")
        plt.scatter(t, w2,c='g')
        
        plt.subplot(223)
        plt.title("w3")
      
        plt.scatter(t, w3,c='b',s=5)
        
        plt.xlabel("t")
        plt.ylabel("w")
        
        
        plt.subplot(224)
        plt.title("loss")
        plt.scatter(t, gradList,c='b',s=5)
        plt.subplots_adjust(bottom=.1, top=.9, left=.01, right=.99,hspace = 0.5)
        
        plt.show()
        
    
            
    def classifyVector(self, X, weights):
        
        Z = X*weights
        
        prob = self.Sigmod(Z)
        
        if prob>0.5:
            return int(1)
        else:
            return int(0)

    def Test(self, W):
        
        errorNum = 0
        
        for i in range(self.m):
            
            X = self.trainData[i]
            
            y =self.classifyVector(X, W)
            
            if y != self.trainLabel[i,0]:
                print("y ",y, "\t true ",self.trainLabel[i,0])
                errorNum +=1
        print("\n  error: ",errorNum/self.m)
            

        

    

lg = MyLogistic()
lg.Train()
lg.Test(lg.W)

 

        

 

            

 

     

          

     

         

 

       

       

            

       

                    

 

          

       

 

  

    

 

   

 

 

   

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值