Python機器學習算法 — 邏輯回歸(Logistic Regression)


邏輯回歸--簡介

        邏輯回歸(Logistic Regression)就是這樣的一個過程:面對一個回歸或者分類問題,建立代價函數,然后通過優化方法迭代求解出最優的模型參數,然后測試驗證我們這個求解的模型的好壞。
        Logistic回歸雖然名字里帶“回歸”,但是它實際上是一種分類方法,主要用於兩分類問題(即輸出只有兩種,分別代表兩個類別)。
        回歸模型中,y是一個定性變量,比如y=0或1,logistic方法主要應用於研究某些事件發生的概率。

邏輯回歸--優缺點

 優點: 
         1、速度快,適合二分類問題 ;
         2、簡單易於理解,直接看到各個特征的權重 ;
         3、能容易地更新模型吸收新的數據 ;
 缺點:
         1、對數據的場景的適應能力有局限性,不如決策樹算法適應性強;

邏輯回歸--用途

用途:
        1、尋找危險因素:尋找某一疾病的危險因素等;
        2、預測:根據模型,預測在不同的自變量情況下,發生某病或某種情況的概率有多大;
        3、判別:實際上跟預測有些類似,也是根據模型,判斷某人屬於某病或屬於某種情況的概率有多大,也就是看一下這個人有多大的可能性是屬於某病

邏輯回歸--原理

Logistic Regression和Linear Regression的原理是相似的,按照我自己的理解,可以簡單的描述為這樣的過程:
      (1)找一個合適的預測函數(Andrew Ng的公開課中稱為hypothesis),一般表示為h函數,該函數就是我們需要找的分類函數,它用來預測輸入數據的判斷結果。這個過程時非常關鍵的,需要對數據有一定的了解或分析,知道或者猜測預測函數的“大概”形式,比如是線性函數還是非線性函數。
      (2)構造一個Cost函數(損失函數),該函數表示預測的輸出(h)與訓練數據類別(y)之間的偏差,可以是二者之間的差(h-y)或者是其他的形式。綜合考慮所有訓練數據的“損失”,將Cost求和或者求平均,記為J(θ)函數,表示所有訓練數據預測值與實際類別的偏差。
      (3)顯然,J(θ)函數的值越小表示預測函數越准確(即h函數越准確),所以這一步需要做的是找到J(θ)函數的最小值。找函數的最小值有不同的方法,Logistic Regression實現時有的是梯度下降法(Gradient Descent)。


邏輯回歸--具體過程

一、構造預測函數

        Logistic回歸雖然名字里帶“回歸”,但是它實際上是一種分類方法,主要用於兩分類問題(即輸出只有兩種,分別代表兩個類別),所以利用了Logistic函數(或稱為Sigmoid函數),函數形式為:


        Sigmoid 函數在有個很漂亮的“S”形,如下圖所示:


       下面左圖是一個線性的決策邊界,右圖是非線性的決策邊界:


      對於線性邊界的情況,邊界形式如下:


      構造預測函數為:


        函數的值有特殊的含義,它表示結果取1的概率,因此對於輸入x分類結果為類別1和類別0的概率分別為:



二、構造損失函數

        Cost 函數和 J 函數如下,它們是基於最大似然估計推導得到的:


    下面詳細說明推導的過程:
        (1)式綜合起來可以寫成:


        取似然函數為:


        對數似然函數為:


        最大似然估計就是求使取最大值時的θ,其實這里可以使用梯度上升法求解,求得的θ就是要求的最佳參數。但是,在Andrew Ng的課程中將 J(θ)  取為下式,即:


        因為乘了一個負的系數-1/m,所以取 J(θ) 最小值時的θ為要求的最佳參數。


三、梯度下降法求的最小值

        求J(θ)的最小值可以使用梯度下降法,根據梯度下降法可得θ的更新過程:

        式中為α學習步長,下面來求偏導:


        θ更新過程可以寫成:



邏輯回歸--實例


# -*- coding: utf-8 -*-

from numpy import *
import matplotlib.pyplot as plt

#從文件中加載數據:特征X,標簽label
def loadDataSet():
    dataMatrix=[]
    dataLabel=[]
    #這里給出了python 中讀取文件的簡便方式
    f=open('testSet.txt')
    for line in f.readlines():
        #print(line)
        lineList=line.strip().split()
        dataMatrix.append([1,float(lineList[0]),float(lineList[1])])
        dataLabel.append(int(lineList[2]))
    #for i in range(len(dataMatrix)):
    #   print(dataMatrix[i])
    #print(dataLabel)
    #print(mat(dataLabel).transpose())
    matLabel=mat(dataLabel).transpose()
    return dataMatrix,matLabel

#logistic回歸使用了sigmoid函數
def sigmoid(inX):
    return 1/(1+exp(-inX))

#函數中涉及如何將list轉化成矩陣的操作:mat()
#同時還含有矩陣的轉置操作:transpose()
#還有list和array的shape函數
#在處理矩陣乘法時,要注意的便是維數是否對應

#graAscent函數實現了梯度上升法,隱含了復雜的數學推理
#梯度上升算法,每次參數迭代時都需要遍歷整個數據集
def graAscent(dataMatrix,matLabel):
    m,n=shape(dataMatrix)
    matMatrix=mat(dataMatrix)

    w=ones((n,1))
    alpha=0.001
    num=500
    for i in range(num):
        error=sigmoid(matMatrix*w)-matLabel
        w=w-alpha*matMatrix.transpose()*error
    return w


#隨機梯度上升算法的實現,對於數據量較多的情況下計算量小,但分類效果差
#每次參數迭代時通過一個數據進行運算
def stocGraAscent(dataMatrix,matLabel):
    m,n=shape(dataMatrix)
    matMatrix=mat(dataMatrix)

    w=ones((n,1))
    alpha=0.001
    num=20  #這里的這個迭代次數對於分類效果影響很大,很小時分類效果很差  
    for i in range(num):
        for j in range(m):
            error=sigmoid(matMatrix[j]*w)-matLabel[j]
            w=w-alpha*matMatrix[j].transpose()*error        
    return w

#改進后的隨機梯度上升算法
#從兩個方面對隨機梯度上升算法進行了改進,正確率確實提高了很多
#改進一:對於學習率alpha采用非線性下降的方式使得每次都不一樣
#改進二:每次使用一個數據,但是每次隨機的選取數據,選過的不在進行選擇
def stocGraAscent1(dataMatrix,matLabel):
    m,n=shape(dataMatrix)
    matMatrix=mat(dataMatrix)

    w=ones((n,1))
    num=200  #這里的這個迭代次數對於分類效果影響很大,很小時分類效果很差
    setIndex=set([])
    for i in range(num):
        for j in range(m):
            alpha=4/(1+i+j)+0.01

            dataIndex=random.randint(0,100)
            while dataIndex in setIndex:
                setIndex.add(dataIndex)
                dataIndex=random.randint(0,100)
            error=sigmoid(matMatrix[dataIndex]*w)-matLabel[dataIndex]
            w=w-alpha*matMatrix[dataIndex].transpose()*error    
    return w

#繪制圖像
def draw(weight):
    x0List=[];y0List=[];
    x1List=[];y1List=[];
    f=open('testSet.txt','r')
    for line in f.readlines():
        lineList=line.strip().split()
        if lineList[2]=='0':
            x0List.append(float(lineList[0]))
            y0List.append(float(lineList[1]))
        else:
            x1List.append(float(lineList[0]))
            y1List.append(float(lineList[1]))

    fig=plt.figure()
    ax=fig.add_subplot(111)
    ax.scatter(x0List,y0List,s=10,c='red')
    ax.scatter(x1List,y1List,s=10,c='green')

    xList=[];yList=[]
    x=arange(-3,3,0.1)
    for i in arange(len(x)):
        xList.append(x[i])

    y=(-weight[0]-weight[1]*x)/weight[2]
    for j in arange(y.shape[1]):
        yList.append(y[0,j])

    ax.plot(xList,yList)
    plt.xlabel('x1');plt.ylabel('x2')
    plt.show()


if __name__ == '__main__':
    dataMatrix,matLabel=loadDataSet()
    #weight=graAscent(dataMatrix,matLabel)
    weight=stocGraAscent1(dataMatrix,matLabel)
    print(weight)
    draw(weight)



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM