Logistic回歸

機(jī)器學(xué)習(xí)實(shí)戰(zhàn)

假設(shè)現(xiàn)在有一些數(shù)據(jù)點(diǎn),我們用一條直線對(duì)這些點(diǎn)進(jìn)行擬合(該線稱為最佳擬合直線),這個(gè)擬合過程就稱作回歸。Logistic回歸進(jìn)行分類的主要思想是:根據(jù)現(xiàn)有數(shù)據(jù)對(duì)分類邊界線監(jiān)理回歸公式,以此進(jìn)行分類。

基于Logistic回歸和Sigmoid函數(shù)

我們想要的函數(shù)應(yīng)該是,能夠接受所有的輸入然后預(yù)測(cè)出類別。例如,在兩個(gè)類的情況下,上述函數(shù)輸出0和1。從0瞬間跳躍到1,這個(gè)跳躍的過程不好處理,我們引入Sigmoid函數(shù)。

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

001QAImHgy6I1ok9Brb61&690.jpg

此函數(shù)當(dāng)x = 0時(shí),Sigmoid函數(shù)值為0.5,隨著x的增大,對(duì)應(yīng)的Sigmoid值將逼近1;而隨著x的減小,Sigmoid逼近于0。
因此為了實(shí)現(xiàn)Logistic回歸分類器,我們可以在每個(gè)特征上都乘以一個(gè)回歸系數(shù),然后把所有的結(jié)果值相加,將這個(gè)總和代入Sigmoid函數(shù)中,進(jìn)而得到一個(gè)范圍在0-1之間的數(shù)值。 任何>0.5的數(shù)據(jù)被分入1類,<0.5的被歸為0類。

基于最優(yōu)化方法的最佳回歸系數(shù)的確定

Sigmoid的函數(shù)輸入記為z,由下面公式得出:
z = w_0x_0 + w_1x_1+w_2x_3+...+w_nx_n 用向量表示為z = w^Tx,表示將這兩個(gè)數(shù)值對(duì)應(yīng)元素相乘然后全部加起來(lái)得到z值。其中x是分類器的輸入數(shù)據(jù),向量w就是我們要找的最佳參數(shù),從而使分類器盡可能精確。

接下來(lái)就是尋找最佳參數(shù)
梯度上升法 基于的思想是:要找到某個(gè)函數(shù)的最大值,最好的方法是沿著該函數(shù)的梯度方向探尋。如果梯度記為\Delta,這函數(shù)f(x,y)的梯度有下式表示:
\Delta{f(x,y)} = f\left( \frac{\partial f(x,y)}{\partial x} \frac{\partial f(x,y)}{\partial x}\right)

imgres [1].jpg

如果所示梯度上升算法沿梯度方向移動(dòng)一步??梢钥吹?,梯度算子總是指向函數(shù)值增長(zhǎng)最快的方向。移動(dòng)量的大小稱為步長(zhǎng),記作\alpha。用向量來(lái)表示的話,梯度算法的迭代公司如下:
w:=w+\alpha\Delta_wf(w);該公式將一直迭代執(zhí)行,直至達(dá)到某個(gè)停止條件為止,比如迭代次數(shù)達(dá)到某個(gè)指定值或算法達(dá)到某個(gè)可以允許的誤差范圍。

from math import *
from numpy import *
import matplotlib.pyplot as plt
#加載數(shù)據(jù)
def loadDataSet():
    dataMat = [];labelMat = []
    fr = open('testSet.txt')
    for line in fr.readlines():
        lineArr = line.strip().split()
        dataMat.append([1.0,float(lineArr[0]),float(lineArr[1])])
        labelMat.append(int(lineArr[2]))
    return dataMat,labelMat

def sigmoid(inX):
    return 1.0/(1+exp(-inX))

'''
dataMatIn 是一個(gè)二維NumPy數(shù)組 每列代表不同的特征 每行代表一個(gè)訓(xùn)練樣本
classLabels  代表的是 樣本的類別
'''
def gradAscent(dataMatIn,classLabels):
    dataMatrix = mat(dataMatIn)
    # 轉(zhuǎn)換NumPy數(shù)據(jù)類型
    labelMat = mat(classLabels).transpose()
    m,n = shape(dataMatrix)
    #向目標(biāo)移動(dòng)的步長(zhǎng)
    alpha = 0.001
    #迭代次數(shù)
    maxCycles = 500
    weights = ones((n,1))
    for k in range(maxCycles):
        h = sigmoid(dataMatrix*weights) #是一個(gè)列向量
        error = (labelMat - h)   #誤差  與真實(shí)值
        weights = weights+alpha*dataMatrix.transpose()*error #調(diào)整
    return weights

'''
繪圖 方便的API 步驟一樣 設(shè)置參數(shù)眾多
'''
def plitBestFit(weights):
    dataMat,labelMat = loadDataSet()
    dataArr = array(dataMat)
    n = shape(dataArr)[0]
    xcord1 = [];ycord1 = []
    xcord2 = [];ycord2 = []
    for i in range(n):
        if int(labelMat[i]) == 1:
            xcord1.append(dataArr[i,1]);ycord1.append(dataArr[i,2])
        else:
            xcord2.append(dataArr[i, 1]);ycord2.append(dataArr[i, 2])
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.scatter(xcord1,ycord1,s=30,c='red',marker='s')
    ax.scatter(xcord2,ycord2,s=30, c='green')
    x = arange(-3.0,3.0,0.1)
    y = (-weights[0] - weights[1]*x)/weights[2]  #0 = w0x0+w1x1 計(jì)算x0的值
    ax.plot(x,y)
    plt.xlabel('X1')
    plt.ylabel('X2')
    plt.show()
if __name__ =='__main__':
    dataArr,labelMat = loadDataSet()
    # print(dataArr)
    # print(labelMat)
    weights = gradAscent(dataArr,labelMat)
    # print(weights)
   plitBestFit(weights.getA())
圖一

隨機(jī)梯度上升算法

梯度上升每次更新回歸系數(shù)時(shí)都需要遍歷整個(gè)數(shù)據(jù)集,該方法處理100個(gè)左右的數(shù)據(jù)集是尚可,但是如果數(shù)據(jù)量巨大,特征比較多,則該方法就不行。一種改進(jìn)的方法就是一次僅用一個(gè)樣本點(diǎn)來(lái)更新回歸系數(shù),該方法稱為隨機(jī)梯度算法。

def stocGradAscent0(dataMatrix,classLabels):
    m,n = shape(dataMatrix)
    print(m,n)
    alpha = 0.01
    weights = ones(n)
    for i in range(m):
        h = sigmoid(sum(dataMatrix[i]*weights)) #每一個(gè)樣本計(jì)算一次
        error = classLabels[i] - h
        weights = weights+alpha*error*dataMatrix[i]
    return weights
if __name__ =='__main__':
    dataArr,labelMat = loadDataSet()
    # print(array(dataArr))
    # print(labelMat)
    weights = stocGradAscent0(array(dataArr),labelMat)
    # # print(weights)
    plitBestFit(weights)
圖二

可以看出最佳擬合直線并不是最佳分類線。

改進(jìn)

'''
 默認(rèn)迭代150次,也可以自由設(shè)定迭代次數(shù)
 1 每次迭代調(diào)整步長(zhǎng)
 2隨機(jī)選取樣本來(lái)更新回歸系數(shù)。每次用列表中隨機(jī)取出一個(gè)值,然后刪除
'''
def stocGradAscent1(dataMatrix,classLabels,numIter = 150):
    m,n = shape(dataMatrix)
    weights = ones(n)
    for j in range(numIter):
        dataIndex = list(range(m))
        for i in range(m):
            alpha = 4/(1.0+j+i)+0.0001   #1
            randIndex = int(random.uniform(0,len(dataIndex))) #2
            h = sigmoid(sum(dataMatrix[randIndex] * weights))
            error = classLabels[randIndex] - h
            weights = weights + alpha * error * dataMatrix[randIndex]
            del(dataIndex[randIndex])
    return weights
圖三
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容