機器學習筆記(6)-邏輯迴歸與最大熵模型

Logistic迴歸

Logistic 迴歸雖然名字叫回歸,但是它是用來做分類的。其主要思想是: 根據現有數據對分類邊界線建立迴歸公式,以此進行分類。假設現在有一些數據點,我們用一條直線對這些點進行擬合(這條直線稱爲最佳擬合直線),這個擬合的過程就叫做迴歸
Sigmoid 函數
Sigmoid 函數具體的計算公式
這裏寫圖片描述

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

爲了實現 Logistic 迴歸分類器,我們可以在每個特徵上都乘以一個迴歸係數(如下公式所示),然後把所有結果值相加,將這個總和代入 Sigmoid 函數中,進而得到一個範圍在 0~1 之間的數值。任何大於 0.5 的數據被分入 1 類,小於 0.5 即被歸入 0 類。所以, Logistic 迴歸也可以被看成是一種概率估計。
Sigmoid 函數的輸入記爲 z ,由下面公式得到:
這裏寫圖片描述

邏輯斯蒂迴歸模型

1. 二項邏輯斯蒂迴歸模型
二項邏輯斯蒂迴歸模型是如下的條件概率分佈:
這裏寫圖片描述
這裏寫圖片描述
這裏寫圖片描述
這裏寫圖片描述
意義:在邏輯斯蒂迴歸模型中,輸出Y=1的對數機率是輸入x的線性函數。或者說,輸出Y=1的對數機率是由屬於x的線性函數表示的模型,即邏輯斯蒂迴歸模型。
感知機只通過決策函數(w⋅x)的符號來判斷屬於哪一類。邏輯斯蒂迴歸需要再進一步,它要找到分類概率P(Y=1)與輸入向量x的直接關係,再通過比較概率值來判斷類別。
令決策函數(w⋅x)輸出值等於概率值比值取對數,即:
這裏寫圖片描述
邏輯斯蒂迴歸模型的定義式P(Y=1|x)中可以將線性函數w⋅x轉換爲概率,這時,線性函數的值越接近正無窮,概率值就越接近1;線性函數的值越接近負無窮,概率值就接近0.
2. 模型參數估計
應用極大似然法進行參數估計,從而獲得邏輯斯蒂迴歸模型。
這裏寫圖片描述
這裏寫圖片描述
上式連乘符號內的兩項中,每個樣本都只會取到兩項中的某一項。若該樣本的實際標籤yi=1,取樣本計算爲1的概率值π(xi);若該樣本的實際標籤yi=0,取樣本計算的爲0的概率值1−π(xi)。
3對數似然函數爲:
這裏寫圖片描述
對上式中的L(w)求極大值,得到w的估計值。
問題轉化成以對數似然函數爲目標函數的無約束最優化問題,通常採用梯度下降法以及擬牛頓法求解w。
假設w的極大估計值是wˆ,那麼學到的邏輯斯蒂迴歸模型爲:
利用梯度上升找到最佳參數
這裏寫圖片描述
這裏寫圖片描述
4. 交叉熵損失函數的求導:邏輯迴歸的另一種理解是以交叉熵作爲損失函數的目標最優化。交叉熵損失函數可以從上文最大似然推導出來。 交叉熵損失函數爲:
這裏寫圖片描述
則可以得到目標函數爲:
這裏寫圖片描述
計算J(θ)對第j個參數分量θj求偏導:
這裏寫圖片描述

def gradAscent(dataMatIn, classLabels):
    '''正常的梯度上升法
    :param dataMatIn: ataMatIn 是一個2維NumPy數組,每列分別代表每個不同的特徵,每行則代表每個訓練樣本。
    :param classLabels: classLabels 是類別標籤,它是一個 1*100 的行向量。爲了便於矩陣計算,需要將該行向量轉換爲列向量,做法是將原向量轉置,再將它賦值給labelMat。
    :return array(weights)-得到的最佳迴歸係數
    '''
    dataMatrix = mat(dataMatIn)
    labelMat = mat(classLabels).transpose()  # 轉化爲矩陣[[0,1,0,1,0,1.....]],並轉制[[0],[1],[0].....]
    m,n = shape(dataMatrix)
    alpha = 0.001     # alpha代表向目標移動的步長
    maxCycles = 500   # 迭代次數
    weights = ones((n,1))  # 生成一個長度和特徵數相同的矩陣
    for k in range(maxCycles):
        h = sigmoid(dataMatrix*weights)     # mxn+nx1->mx1
        error = (labelMat - h)
        weights = weights + alpha * dataMatrix.transpose() * error # 矩陣乘法,最後得到迴歸係數
    return array(weights)

梯度上升優化算法在每次更新數據集時都需要遍歷整個數據集,計算複雜都較高;改進方法爲隨機梯度上升:一次只用一個樣本點來更新迴歸係數。

def stocGradAscent0(dataMatrix, classLabels):
    m,n = shape(dataMatrix); alpha = 0.01
    weights = ones(n)   
    for i in range(m):
        h = sigmoid(sum(dataMatrix[i]*weights))
        error = classLabels[i] - h
        print weights, "*"*10 , dataMatrix[i], "*"*10 , error
        weights = weights + alpha * error * dataMatrix[i]
    return weights

改進的隨機梯度上升算法:1,alpha在每次迭代的時候都會調整;2,通過隨機選取樣本來更新迴歸係數;

def stocGradAscent1(dataMatrix, classLabels, numIter=150):
    '''
    :param dataMatrix: 輸入數據的數據特徵(除去最後一列數據)
    :param classLabels: 輸入數據的類別標籤(最後一列數據)
    :param numIter: 迭代次數
    :return: weights -- 得到的最佳迴歸係數
    '''
    m,n = shape(dataMatrix)
    weights = ones(n)   # 創建與列數相同的矩陣的係數矩陣,所有的元素都是1
    for j in range(numIter):  # 隨機梯度, 循環150,觀察是否收斂
        dataIndex = range(m)
        for i in range(m):
            alpha = 4/(1.0+j+i)+0.0001    # alpha 會隨着迭代不斷減小,但永遠不會減小到0,因爲後邊還有一個常數項0.0001
            randIndex = int(random.uniform(0,len(dataIndex)))  # random.uniform(x, y) 方法將隨機生成下一個實數,它在[x,y]範圍內,x是這個範圍內的最小值,y是這個範圍內的最大值。
            h = sigmoid(sum(dataMatrix[randIndex]*weights))  # sum(dataMatrix[i]*weights)爲了求 f(x)的值, f(x)=a1*x1+b2*x2+..+nn*xn
            error = classLabels[randIndex] - h
            weights = weights + alpha * error * dataMatrix[randIndex]
            del(dataIndex[randIndex])
    return weights

根據權重用logistic畫最佳擬合直線

def plotBestFit(dataArr, labelMat, weights):
    '''將我們得到的數據可視化展示出來
    :param dataArr: 樣本數據的特徵
    :param labelMat: 樣本數據的類別標籤,即目標變量
    :param weights: 迴歸係數
    :return: 
    '''
    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]
    ax.plot(x, y)
    plt.xlabel('X'); plt.ylabel('Y')
    plt.show()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章