機器學習(6)——從線性迴歸到邏輯斯特迴歸

Linear Regression

在學習李航《統計學習方法》的邏輯斯特迴歸時,正好coursera上相應的線性迴歸和邏輯斯特迴歸都學習完成,在此就一起進行總結,其中圖片多來自coursera課程上。
線性迴歸是機器學習中很好理解的一種算法。我們以常見的房屋銷售爲例來進行簡單分析:
假設我們統計的一個房屋銷售的數據如下:
這裏寫圖片描述
在此,我們從單一變量談起,直觀上比較容易理解。訓練集定義爲{(x(1),y(1)),(x(2),y(2)),,(x(m),y(m))} ,其中x 是輸入特徵,y 是輸出目標,m 是樣本的總數目。線性迴歸的最終目的如下所示,就是通過學習,得到一個擬合函數,使得通過輸入特徵就能預測目標輸出值,本例即通過房屋大小估計房屋價格。
這裏寫圖片描述

假設空間

實際線性迴歸假設能夠擬合各種不同的曲線,實際的房子價格可能與房間面積、房間廳室、房間朝向等多個變量有關,我們可以定義特徵x={x1,x2,,xi} 那麼我們可以定義擬合函數爲:

h(x)=hθ(x)=θ0+θ1x1+θ2x2++θixi=θTx

其中 θT=[θ0,θ1,,θi],xT=[x1,x2,,xi] ,最後是其向量表達形式。我們可以看出,每一組θ 值對應一個擬合函數,爲了選出其中最好的θ ,我們定義一個評價標準,即損失函數(loss function)或代價函數(cost function)。

代價函數

在線性迴歸中,我們定義代價函數爲:

J(θ)=1mi=1m12(hθ(x(i))y(i))2

minθJθ

其中,係數12 是爲了求導方便,1m 在不同的講義中可能會有所不同,我們以斯坦福的講義爲標準。
從表達式我們可以看出,學習的最終目的就是優化代價函數,使代價函數變小了,預測值和真值的差異就越小,訓練出來的模型就越好。如何求解J(θ) 有很多種辦法,常見的有梯度下降法和最小二乘法。

梯度下降法

梯度下降法是求解無約束最優化問題的一種最常見的方法,其實現簡單,易於理解。如下圖所述帶有二元參數的目標函數J(θ0,θ1) ,求解其最小值。我們可以初始化一個參數值(θ0,θ1) ,然後求J(θ0,θ1) 在各個方向的偏導,通過一個學習步長來改變參數,並最終求得J(θ0,θ1) 的最小值。具體算法流程爲:

  • Algorithm 6.1
  • initialize θθ={0,0,,0}
  • for k = 1 : NumIter do
  •     θj=θjαθjJ(θ)
  • end for
    在線性線性迴歸中:

    θjJ(θ)=1mi=1m(hθ(x(i))y(i))xij

    其中xij 是第i 個樣本實例的第j 維特徵。由此我們就可以學習出每個特徵的參數。
    這裏寫圖片描述
    在梯度下降法中有兩個個關鍵參數選擇:學習率α 和初始化θ
  • 對於合適的學習率α ,目標函數 J(θ) 在每次迭代中都會減小,因此可以通過J(θ) 的值檢測算法的正確性。在實際操作中,α 太小,算法的收斂速度會很慢,當α 太大時,則會出現震盪,學習不到最佳參數。

  • 對於初始參數θ ,不同的起點,可能會得到不同的最優解,即陷入局部最優。

最小二乘法

梯度下降法需要不斷的迭代計算,一般來說,收斂速度都會比較慢,另一種快速求解最佳解的方法是最小二乘法,具體公式爲:

θ=(XTX)1XTY

在自我編程實現中,矩陣逆的求解是一個難點。另外,也存在不可解的情況:一是特徵相互關聯,不獨立;二是樣本數少於特徵數,可能使得矩陣的逆不存在。

過擬合和正則化

過擬合是機器學習中很普遍的例子,指的是訓練模型在訓練集上有很好的分類迴歸效果,但是在新的測試數據集上表現卻很差,即模型的泛化能力差。
如下圖所示,依舊以“大小-房價”線性迴歸爲例來說明。房價與房屋大小可能是非線性關係,如圖1所示,假設模型爲θ0+θ1x ,即線性關係,擬合效果不好,稱爲欠擬合;圖2則是非線性擬合,假設模型爲θ0+θ1x+θ2x2 ,能夠比較好的擬合兩者之間的關係;圖3所示的多項式θ0+θ1x+θ2x2+θ3x3+θ4x4 則能夠擬合所有的數據,即對訓練樣本的學習效果很好,但是這明顯不是我們所期望的學習模型,存在嚴重過擬合。
這裏寫圖片描述
解決過擬合問題常有以下幾種方式:

  • 減少特徵數量
       - 人爲選擇特徵,去掉不必要的特徵
       - 機器學習選擇特徵,主成分分析降維等
  • 正則化
       - 保持所有特徵,但是減小學習參數θ 的值。
    如上圖3所示,通過懲罰項使最終的學習參數θ3,θ4 極小,則最終模型與圖2模型很相近。即:

    min1m{i=1m(hθ(x(i))y(i))+1000θ23+1000θ24}

    通過將θ3,θ4 帶入到損失函數中,使函數考慮模型複雜度的影響。正則化的目的就是將模型的複雜度考慮到代價函數中,使模型趨於簡單,不易過擬合。對於線性迴歸,正則化代價函數爲:
    J(θ)=12m[i=1m(hθ(x(i))y(i))2+λi=1nθ2j]

    其中,前面一部分是對訓練數據集的擬合誤差,後一部分正則化項是對模型複雜度的約束,λ 是調節兩則之間的權重:
  • λ 較小時,極限情況下λ=0 ,則不考慮模型的複雜度,是原有的損失函數

  • λ 較大時,則訓練的參數很小,模型可能會欠擬合

Logistic Regression

迴歸問題一般是連續預測:如房價預測、銷售額預測,即輸出y 的狀態可能有無限多種;
分類問題則是離散預測:郵件分類(垃圾/正常),細胞檢測(正常/癌變),輸出一般對應有限狀態。
一般來說,線性迴歸不能直接用於分類問題,因爲迴歸是連續性模型,而且受噪音比較大,我們一般選擇logistic迴歸來進行分類。logistic本質是線性迴歸,只是在特徵到結果的映射中加入了一層映射函數。

邏輯斯特迴歸模型

對於二分類系統,我們希望學習模型的輸出爲0或1,對於固定的特徵,我們希望學習模型預測其屬於正例的概率。即:hθ(x)=P(y=1|x:θ) ,對於二分類系統,P(y=1|x:θ)+P(y=0|x:θ)=1 。logistic的假設函數爲:

hθ(x)=g(θTx)=11+eθTx

如下圖所示,我們定義邏輯斯特迴歸的學習規則爲:
  • θTx0 ,則hθ(x)0.5 ,此時認爲樣本屬於正樣本的概率更大,即y=1
  • θTx<0 ,則hθ(x)<0.5 ,此時認爲樣本屬於正樣本的概率更大,即y=0
    這裏寫圖片描述

決策邊界

對於分類問題,最終就是得到一個分類邊界,使樣本能夠被準確區分開。如下圖所示的兩類樣本,我們假設紅色爲正樣本,即y=1 ,藍色爲負樣本,即y=0 。分類決策面有兩個特徵x1,x2 ,因此我們定義假設模型爲:hθ(x)=g(θ0+θ1x1+θ2x2) 。取θT=[3,1,1] ,即分類平面爲3+x1+x2=0 ,我們可以看到:

  • 3+x1+x20 時,即θTx0 ,此時有hθ(x)0.5 ,決策爲正樣本,從圖中我們可以看到3+x1+x2=0 右上側爲正樣本
  • 同理,當3+x1+x2<0 時,即θTx<0hθ(x)<0.5 ,決策爲負樣本。
    通過該直線我們可以將二分類樣本正確區分開,這樣的邊界也稱爲決策邊界。如果樣本是非線性可分的,我們也可以通過複雜多項式進行分類。邏輯斯特迴歸最終學習到的模型就是這樣的邊界圖,在邊界的兩邊就是兩個不同的類別。
    這裏寫圖片描述

損失函數

邏輯斯特迴歸代價函數一般定義爲:

Cost(hθ(x),y)={log(hθ(x)),log(1hθ(x)),if y=1if y=0

因爲hθ(x) 是輸出爲(0,1)之間的函數,如果真值爲y=1 ,預測值hθ(x) 越接近1,代價越小,即預測越正確。同理,真值爲y=0 ,預測值hθ(x) 越接近0,代價越小,即預測越正確。我們可以將代價函數改寫爲:
Cost(hθ(x),y)=ylog(hθ(x))(1y)log(1hθ(x))

最終的代價函數爲:
J(θ)=1mi=1m[y(i)log(hθ(x(i)))+(1y(i))log(1hθ(x(i)))]

如果考慮模型的複雜度,即加入正則項,則爲:
J(θ)=1mi=1m[y(i)log(hθ(x(i)))+(1y(i))log(1hθ(x(i)))]+12mj=1nθ2j

最終目標是最小化目標函數,用梯度下降法求解,則:
θjJ(θ)=1mi=1m[y(i)1hθ(x(i))hθ(x(i))(1y(i))11hθ(x(i))hθ(x(i))]=1mi=1m[y(i)y(i)hθ(x(i))hθ(x(i))+y(i)hθ(x(i))hθ(x(i))(1hθ(x(i)))]hθ(x(i))=1mi=1m[y(i)hθ(x(i))11+eθTxeθTx1+eθTx]eθTx(1+eθTx)2x(i)j=1mi=1m(hθ(x(i))y(i))x(i)j

通過推導我們發現邏輯斯特迴歸的代價函數與線性迴歸形式上很像,不同之處在於模型假設不一樣,線性迴歸是hθ(x)=θTx , 而邏輯迴歸在此基礎上多了一層映射hθ(x)=11+eθTx

多分類問題

logistic迴歸也可用於擴展用於多分類問題,解決辦法常見的就是一對多。如下圖所示有三類樣本,我們可以先用一個分類器將類別一與另外兩類區分開(右圖1),然後用同樣的辦法訓練兩個分類器,將每個類別區分開。在得到的三個假設模型中,我們計算每個樣本在每個模型中的值,即概率,通過選取最大的概率,就能確定樣本所屬的類別。
這裏寫圖片描述

Python實現

最後我們通過Python實現了簡單的logistic二分類問題,具體代碼如下:
讀取txt文件中的訓練數據,包含特徵和標籤,並給特徵加上偏置項1

# load training data set
def loadData(path):
    dataMat = []; labelMat = [];
    f = open(path)
    data= f.read().split()
    for datastring in data:
        dataMat.append([1,float(datastring.split(',')[0]),float(datastring.split(',')[1])])
        labelMat.append(int(datastring.split(',')[2]))
    return dataMat,labelMat

從txt中讀取的特徵值很大,進行標準歸一化之後進行訓練。

def featureNormalize(dataMat):
    dataMatrix = mat(dataMat)
    data_norm = dataMatrix;
    m,n = shape(dataMatrix)
    mu = mean(dataMatrix[:,1:3],axis = 0)
    sigma = std(dataMatrix[:,1:3],axis = 0)
    data_norm[:,1:3]= [x/y for x,y in zip((dataMatrix[:,1:3]-tile(mu,(m,1))),tile(sigma,(m,1)))]
    return data_norm,mu,sigma

繪製最終分類效果圖和損失函數的變化

# plot data set
def plotdata(theta,mu,sigma,dataMat,labelMat):
    dataArr = array(dataMat)
    positive_x =[]; positive_y = []
    negtive_x =[]; negative_y = []
    for i in range(len(labelMat)):
        if 1 == int(labelMat[i]):
            positive_x.append(dataArr[i,1]);positive_y.append(dataArr[i,2])
        else:
            negtive_x.append(dataArr[i,1]);negative_y.append(dataArr[i,2])
    fig1 = plt.figure('fig1')
    ax = fig1.add_subplot(111)
    ax.scatter(positive_x,positive_y,s=30,c='red',marker='s')
    ax.scatter(negtive_x,negative_y,s=30,c='green')
    min_x = min(dataArr[:,1])
    max_x = max(dataArr[:,1])
    y_min_x = (-theta[0]-theta[1]*(min_x-mu[0,0])/sigma[0,0])*sigma[0,1]/theta[2]+mu[0,1]
    y_max_x = (-theta[0]-theta[1]*(max_x-mu[0,0])/sigma[0,0])*sigma[0,1]/theta[2]+mu[0,1]
    ax.plot([min_x,max_x],[y_min_x,y_max_x],'-g')
    plt.xlabel('X1');plt.ylabel('X2');plt.legend();
    plt.show()

# plot cost
def plotJ(J_history):
    fig2 = plt.figure('fig2')
    ax = fig2.add_subplot(111)
    x = arange(0,len(J_history),1)
    ax.plot(x,J_history)
    plt.xlabel('Iter');plt.ylabel('cost');plt.legend();
    plt.show()

梯度下降算法:

# sigmoid function
def sigmoid(z):
    return 1.0 / (1+exp(-z))

# train 
def gradientReg(dataMat,labelMat,alpha,lambda1,MaxIter):
    dataMatrix = mat(dataMat)
    labelMatrix = mat(labelMat).transpose()
    m,n = shape(dataMatrix)
    J = zeros((MaxIter,1))
    theta = zeros((n,1))
    for k in range(MaxIter):
        h = sigmoid(dataMatrix*theta)
        J[k] = 1.0/m*sum(-multiply(labelMatrix,log(h))-multiply((1-labelMatrix),log(1-h)))+\
        lambda1/(2*m)*(sum(theta[2:n]**2))
        error = (h-labelMatrix)
        for i in range(n):
            if 0 == i:
                theta[i] = theta[i] - alpha*1.0/m*(error.transpose()*dataMatrix[:,i])
            else:
                theta[i] = theta[i] - alpha*1.0/m*(error.transpose()*dataMatrix[:,i]+lambda1*theta[i]) 
    return theta,J  

通過訓練模型進行分類預測

# predict 
def predict(theta,dataMat):
    prob = sigmoid(dataMat*theta)
    p = double(prob>0.5)
    return p;

主函數

# main
if __name__=="__main__":
    dataMat = []; labelMat = [];
    alpha = 0.1;lambda1 = 0; MaxIter = 1000;
    datapath = 'F:\Program\Python\Machine_Learning\Logistic\src\ex2data1.txt'
    dataMat,labelMat=loadData(datapath)
    data_norm,mu,sigma =featureNormalize(dataMat)
    theta,J_history = gradientReg(data_norm,labelMat,alpha,lambda1,MaxIter)
    plotdata(theta,mu,sigma,dataMat,labelMat)
    plotJ(J_history)
    p = predict(theta,data_norm)
    print "the classify accuracy is:%.3f%%" %(mean(double(p.transpose() == labelMat)) * 100)

α=0.1,λ=0 時,分類效果圖爲:
這裏寫圖片描述
α=0.1,λ=10 時,分類效果圖爲:
這裏寫圖片描述
α=1,λ=0 時,分類效果圖爲:
這裏寫圖片描述
通過對比圖1和圖2,可以發現當調節參數λ 變化時,代價函數會改變,分類效果和分類結果都會變化,說明它通過引入正則項可以改變模型的複雜程度;通過對比圖1和圖3,可以發現,在一定範圍內α 越大,代價函數收斂越快,模型學習迭代次數越少,但是模型最終分類效果和分類結果都沒變化,學習率隻影響了模型訓練速度,而不會影響模型的性能。

PS:
本文主要參考了李航《統計學習方法》和斯坦福的在線課程,圖表也多引用自斯坦福課程,主要用於自我學習總結,代碼完整示例見此處

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章