統計學習方法6_1.邏輯斯蒂迴歸(logistics迴歸)

1.邏輯斯蒂迴歸、邏輯斯蒂分佈、對數機率

首先,邏輯斯蒂迴歸的公式爲:
P(Y=1X)=exp(wx)1+exp(wx) P(Y=1|X)=\frac{exp(w·x)}{1+exp(w·x)}
P(Y=0X)=11+exp(wx) P(Y=0|X)=\frac{1}{1+exp(w·x)}

對於輸入x,代入上述公式,我們可求出P(Y=1|x)的概率,0<=P(Y=1x)<=10<=P(Y=1|x)<=1
P(Y=1x)P(Y=1|x)的公式來源於邏輯斯蒂分佈
在這裏插入圖片描述在這裏插入圖片描述
由此分佈可以看出,P(Y=1x)P(Y=1|x)的公式來與此分佈相同,因此其對應的圖像與F(x)圖像相同。
同時對應的對數機率爲logit(p)=logP(Y=1x)1P(Y=1x)=wxlogit(p)=log\frac{P(Y=1|x)}{1-P(Y=1|x)}=w·xwxw·x對應的爲整個實數域,即通過logit變換可將p對應於整個實數域,即將【0,1】與wxw·x一一對應起來,取上述logit的反函數即爲P(Y=1X)=exp(wx)1+exp(wx)P(Y=1|X)=\frac{exp(w·x)}{1+exp(w·x)}

2.參數求解

而此時的我們可利用極大似然估計對上述參數進行求解,首先似然函數如下圖所示
在這裏插入圖片描述然後我們需要做的就是極大化上述的L(w)L(w),具體的求解方法可以用梯度下降法、牛頓法等。(疑問:而此時logistics迴歸爲什麼不直接採用梯度爲0求解?)——link 雖然有時候能夠通過直接令梯度爲0求得,但通過梯度上升也能夠得到差不多最優的結果。最重要的是有的時候不能通過直接令梯度等0直接求出結果,但總能通過梯度上升求出。(極大化——梯度上升/極小化——梯度下降)
具體的l(w)=i=1N[yi(wxi)log(1+exp(wxi))]l(w)=\sum_{i=1}^{N}{[y_i(w·x_i)-log(1+exp(w·x_i))]}wiw_i梯度爲:
lwj=i=1N(yiexp(wxi)1+exp(wxi))xij \frac{\partial l}{\partial w_j} =\sum_{i=1}^{N}(y_i-\frac{exp(w·x_i)}{1+exp(w·x_i)})x_i^j
然後梯度上升的公式爲:
wj=wj+αi=1N(yiexp(wxi)1+exp(wxi))xijw_j = w_j+\alpha \sum_{i=1}^{N}(y_i-\frac{exp(w·x_i)}{1+exp(w·x_i)})x_i^j
對應到向量的運算爲:
w=w+αi=1N(yiexp(wxi)1+exp(wxi))xi\textbf{w} =\textbf{w}+\alpha \sum_{i=1}^{N}(y_i-\frac{exp(\textbf{w}·x_i)}{1+exp(\textbf{w}·x_i)})x_i
上述爲批量梯度下降的公式,具體到隨機梯度下降上:
w=w+α(yiexp(wxi)1+exp(wxi))xi\textbf{w}=\textbf{w}+\alpha (y_i-\frac{exp(\textbf{w}·x_i)}{1+exp(\textbf{w}·x_i)})x_i

總結:

以上,就是這次對邏輯斯蒂迴歸的大致介紹,我們首先介紹了邏輯斯蒂迴歸對應的公式,然後介紹了他與邏輯斯蒂分佈以及對數機率之間的關係;然後介紹模型的參數求解,使用極大似然估計方法求解,先寫出似然函數,然後可以利用梯度下降/牛頓法等用於求解無約束優化問題的這類方法來對參數進行求解。最後,將會附上一個minist數據集對應的手寫邏輯斯蒂迴歸方法實現的分類。

附:邏輯斯蒂迴歸實現(minist數據集)

參考:https://www.pkudodo.com/2018/12/03/1-6/#comment-454

import numpy as np
import datetime
'''
minist 數據集
50000 訓練集
10000 測試集(實際使用200)
訓練結果:
time_cost 295
currencies  0.902
'''

def load_data(fileName):#加載數據
    '''
    :param fileName:minist訓練集/測試集文件
    :return: 對應的特徵值X和標籤值Y
    '''
    fr = open(fileName, 'r')
    dataX = [];dataY = []
    for line in fr.readlines():
        lineArr = []
        curline = line.strip().split(',')
        if(curline[0]=='0'):# 二分類問題 轉換爲區分0和非0數字
            dataY.append(1)  # 標籤
        else:
            dataY.append(0)
       	#dataX.append([int(num) for num in curline[1:]])  # 特徵
        dataX.append([int(num)/255 for num in curline[1:]])  # 特徵
        '''
        /255是進行歸一化
        如果不進行歸一化 則將如下代碼
        if(curline[0]=='0'):# 二分類問題 轉換爲區分0和非0數字
            dataY.append(1)  # 標籤
        else:
            dataY.append(0)
        改爲:
           if(curline[0]=='0'):# 二分類問題 轉換爲區分0和非0數字
            dataY.append(0)  # 標籤
        else:
            dataY.append(1)
        則正確率會很低
       但進行歸一化之後,就不會有上述問題
        '''
    # print(dataX)
    return dataX, dataY
def logistics_Regression(trainX,trainY,iter=200):
    '''
    對模型進行訓練
    :param trainX: 訓練集特徵x
    :param trainY:訓練集標籤y
    :param iter:迭代次數
    :return:返回學習到的參數w
    '''
    # 將w·x+b變爲w·x
    for i in range(len(trainX)):
        trainX[i].append(1)
    #將列表轉換爲數組 便於運算
    trainX = np.array(trainX)
    # 權值數組大小
    w = np.zeros(trainX.shape[1])
    #步長
    h = 0.001
    for i in range(iter):#迭代次數
        for j in range(trainX.shape[0]):
            # np.dot 點乘 矩陣相乘 a × b 、b×c ==> a × c
            # * np.multiply() 對應元素相乘
            wx = np.dot(w,trainX[j])
            w += h*(trainY[j]*trainX[j] - trainX[j]*np.exp(wx)/(1+np.exp(wx)))
        if i%20==0:
            print('{:.2%}...'.format(i/200))
    return w
def predict(w,X):
    '''
    進行結果預測
    :param w: 訓練好的參數
    :param X: 待預測的樣本特徵
    :return: 預測結果
    '''
    p = np.exp(np.dot(w,X))/(1+np.exp(np.dot(w,X)))
    if(p>=0.5):
        return 1
    else:
        return 0
def test(testX,testY,w):
    '''
    進行測試集的相關測試
    :param testX:測試集特徵
    :param testY: 測試集標籤
    :param w: 參數
    :return: 正確率
    '''
    for i in range(len(testX)):
       testX[i].append(1)
    count = 0
    for i in range(len(testX)):
        if testY[i] == predict(w,testX[i]):#進行測試
            count+=1
    return float(count/len(testX))

if __name__ == "__main__":
    print("start read data...")
    trainX, trainY = load_data("./mnist_train/mnist_train.csv")
    testX, testY = load_data("./mnist_test/mnist_test.csv")  # 進行測試
    # (60000,784) (60000,1)
    # testX = np.mat(testX)
    start = datetime.datetime.now()
    print("start train the model...")
    w = logistics_Regression(trainX, trainY)
    print("start test...")
    acc = test(testX,testY,w)
    end = datetime.datetime.now()
    print("time_cost", (end - start).seconds)
    print("currencies ", acc)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章