1. 程式人生 > >《機器學習實戰》logistic迴歸:關於’此處略去了一個簡單的數學推導‘的個人理解

《機器學習實戰》logistic迴歸:關於’此處略去了一個簡單的數學推導‘的個人理解

正在看《機器學習實戰》這本書的朋友,在看到logistic迴歸的地方,可能會對P78頁的梯度上升演算法程式碼以及P79這裡的這句話弄的一頭霧水:“此處略去了一個簡單的數學推導,我把它留給有興趣的讀者”。這句話就是針對下面這段我貼出來的程式碼中的gradAscent函式說的。
在這裡插入圖片描述
我當時是想不明白為什麼特徵值矩陣的轉置:dataMatrix.transpose(),它與真實類別/預測類別二者之間的差做矩陣乘法得到的結果,就被直接當作梯度了。

於是上網搜了下關於這部分內容的解釋,baidu搜到的前兩條連結裡的內容都是基於均方誤差(最小二乘法)作為代價函式對於此處做的數學解釋。其他的搜尋結果也未給予詳細的數學推導過程。

而看過Andrew.N.G公開課logistic迴歸這一章的朋友,想必不會忘記吳老師關於logistic迴歸的代價函式處的額外補充,有別於線性迴歸,logistic迴歸如果依舊採用均方誤差作代價函式,那麼應用梯度下降法進行優化效果不會很理想(由於非凸,存在區域性最優值),再翻看一下李航老師的《統計學習方法》一書,也能發現logistic迴歸的“策略”也是求取對數似然函式的極大值為目標,而非求取均方誤差函式的極小值。

二來,上述程式碼是“梯度上升演算法”的實現,如果拿均方誤差函式作為代價函式,那豈不是助紂為虐,代價越來越大麼?

基於上述兩點疑問,決定自己做一下數學推導,推導過程如下:
在這裡插入圖片描述
在這裡插入圖片描述
推導過程除了符號複雜一些,真的不難。。。就是單純的求偏導數而已

接下來是對程式碼中的過程進行下數學驗證:
在這裡插入圖片描述
在這裡插入圖片描述
到這裡,我們就可以發現,正常的數學推導得到的梯度跟程式碼中dataMatrix.transpose()*error是一模一樣的。

補充:作者也是剛剛入門機器學習,本著較真的勁兒嘗試著用均方誤差做代價函式,看一看是不是存在很多區域性最優值。。。
以這本書附帶的資料集做為例子,設定了10000個權重向量,觀察一下代價函式的影象。
以下是程式碼:

# -*- coding: utf-8 -*-
"""
Created on Wed Sep 26 19:40:20 2018

@author: _Miracle
本檔案為驗證logistic迴歸使用均方誤差函式作代價函式不可行
"""

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

def loadData():
    dataMat = []
    labelMat = []
    fr = open(r'C:\Users\_Miracle\Desktop\machinelearninginaction-master\Ch05\testSet.txt')
    for line in fr.readlines():
        lineArr = line.strip().split()
        dataMat.append([float(lineArr[0]),float(lineArr[1])])
        labelMat.append(int(lineArr[2]))
    return dataMat,labelMat

def sigmoid(intX):
    return 1.0/(1+np.exp(-intX))


sampleData,classLabel = loadData()
sampleDataMat = np.array(sampleData)

print ('這是特徵資料值(100X2),100個樣本,每個樣本兩個特徵')
print (sampleDataMat)

#比較笨的方法,生成二維普通的list,然後呼叫
m,n = np.shape(sampleDataMat)
newListofList = []
for i in range(m):
    newList = []
    newList.append(classLabel[i])
    newListofList.append(newList)
classLabelMat = np.array(newListofList)

print ('這是每個樣本的類別(100X1),100個樣本就有100個實際類別')
print (classLabelMat)

a = np.arange(m)
a = np.tile(a,(1,m))
#將a變為形如[[0,1,2,0,1,2,···,0,1,2]]重複arange(100)100次的ndarray
b = np.arange(m)
b = np.tile(b,(m,1))
b = b.transpose()
b = b.reshape(1,10000)
#將b處理成形如[[0,0,0,1,1,1,2,2,2]]這種0-99各重複100次的ndarray
#將a,b處理成這個樣子是為了生成一個2x10000的矩陣,使得有10000種權重搭配的可能
weights = np.vstack((a,b))

#weights是權重,此檔案中假設函式暫定為h(x)=1/1+exp(-w1*x1-w2*x2)
#未加入偏置b(就是w0*x0),以便作圖直觀一些
#weights為2X10000的均勻序列,為要觀察代價函式的變化

suppose = sigmoid(sampleDataMat.dot(weights))
print ('此處為假設函式輸出的結果')
print (suppose)
print (np.shape(suppose))
print (suppose[0][0])

#隨手檢驗一下假設函式的所有輸出是否有問題
for i in range(len(suppose)):
    for j in range(len(suppose[i])):
        if suppose[i][j]>1 or suppose[i][j]<0:
            print ('有問題')

classLabelMat = np.tile(classLabelMat,(1,10000))
print ('將實際標籤沿著1軸重複10000次,以便一百萬個結果都能做差')
print (classLabelMat)

#下面註釋掉的autoNorm函式為均值歸一化
#加入了特徵縮放會讓影象變得更加平滑一點
#不加入均值歸一化的話,影象震盪的會明顯一些
#想看看加入效果的話,直接開啟註釋即可,無需進行其他操作
'''def autoNorm(dataSet):
    minVals = dataSet.min(0)
    maxVals = dataSet.max(0)
    ranges = maxVals - minVals
    normDataSet = np.zeros(np.shape(dataSet))
    m = dataSet.shape[0]
    normDataSet = dataSet - np.tile(minVals,(m,1))
    normDataSet = dataSet/np.tile(ranges,(m,1))
    return normDataSet,ranges,minVals

sampleDataMat,xxx,yyy = autoNorm(sampleDataMat)
'''

def costFunction(a,b):
    #下面為計算代價函式的具體程式碼過程
    #由於已知資料集有100個樣本,遂以下進行重組資料結構的時候直接傳入具體數字而非m了
    a = np.tile(a,(1,100))
    b = np.arange(100)
    b = np.tile(b,(100,1))
    b = b.transpose()
    b = b.reshape(1,10000)
    weights = np.vstack((a,b))
    costConsequence = sigmoid(sampleDataMat.dot(weights))-classLabelMat
    costConsequence = costConsequence**2
    costConsequence = costConsequence.sum(0)/200
    costConsequence = costConsequence.reshape((100,100))
    return costConsequence
 
#橫縱座標為0-99的均勻序列,X為權重w1,Y為權重w2    
X=np.arange(m)
Y=np.arange(m)

#繪製代價函式costFunction(w1,w2)的變化3D圖
cost = costFunction(X,Y)
X,Y=np.meshgrid(X,Y)
fig=plt.figure()
ax = Axes3D(fig)
ax.plot_surface(X, Y, cost, rstride = 1, cstride = 1, cmap='rainbow')


    

最後是程式碼的執行結果,代價函式的影象(未進行特徵縮放):
在這裡插入圖片描述

從圖中我們可以看出(儘管不是非常明顯),在很多區域,確實存在多個波動,那麼使用梯度下降等優化演算法時,容易陷入區域性最優解的確是個令人頭疼的問題。