機器學習實戰之 Logistic算法

Logistic 迴歸

1.基本步驟

Logistic迴歸:實際上屬於判別分析,因擁有很差的判別效率而不常使用。

邏輯迴歸的一般過程

1)        收集數據:採用任意方法收集數據。

2)        準備數據:由於需要進行距離計算,因此要求數據類型爲數值型。另外,結構化數據格式則最佳。

3)        分析數據:採用任意方法對數據進行分析。

4)        訓練算法:大部分時間將用於訓練,訓練的目的是爲了找到最佳分類迴歸係數。

5)        測試算法:一旦訓練步驟完成,分類將會很快。

6)        使用算法:首先,我們需要輸入一些數據,並將其轉換成對應的結構化數值;接着,基於訓練好的迴歸係數就可以對這些數值進行簡單的迴歸計算,判定它們屬於哪個類型;在這之後,我們就可以在輸出的類別上作一些其他的分析工作。

優點:

1.       計算複雜度低,易於實施

2.       表示形式易於翻譯

缺點:

易於欠擬合,

2.原理

2.1常規步驟

Regression問題的常規步驟爲:

  1. 尋找h函數(即hypothesis);
  2. 構造J函數(log損失函數);
  3. 想辦法使得J函數最小並求得迴歸參數(θ)

2.2構造預測函數h

Logistic迴歸雖然名字裏帶迴歸,但是它實際上是一種分類方法,主要用於兩分類問題(即輸出只有兩種,分別代表兩個類別),所以利用了Logistic函數(或稱爲Sigmoid函數),函數形式爲:

Sigmoid 函數在有個很漂亮的“S”形,如下圖所示(引自維基百科):

 

下面左圖是一個線性的決策邊界,右圖是非線性的決策邊界。


對於線性邊界的情況,邊界形式如下:


構造預測函數爲:


函數的值有特殊的含義,它表示結果取1的概率,因此對於輸入x分類結果爲類別1和類別0的概率分別爲:


2.3構造損失函數J

損失函數使用log損失函數。Cost函數和J函數如下,它們是基於最大似然估計推導得到的。


下面詳細說明推導的過程:

1)式綜合起來可以寫成:

取似然函數爲:

對數似然函數爲:


最大似然估計就是求使取最大值時的θ,其實這裏可以使用梯度上升法求解,求得的θ就是要求的最佳參數。但是,在Andrew Ng的課程中將取爲下式,即:


因爲乘了一個負的係數-1/m,所以取最小值時的θ爲要求的最佳參數。


梯度下降法求的最小值

θ更新過程:

 


θ更新過程可以寫成:

 


向量化Vectorization

Vectorization是使用矩陣計算來代替for循環,以簡化計算過程,提高效率。

如上式,Σ(...)是一個求和的過程,顯然需要一個for語句循環m次,所以根本沒有完全的實現vectorization。


下面介紹向量化的過程:

約定訓練數據的矩陣形式如下,x的每一行爲一條訓練樣本,而每一列爲不同的特稱取值:

g(A)的參數A爲一列向量,所以實現g函數時要支持列向量作爲參數,並返回列向量。由上式可知可由一次計算求得。

θ更新過程可以改爲:


綜上所述,Vectorization後θ更新的步驟如下:

(1)求

(2)求

(3)求 

3.Python 求解Logistic 迴歸

訓練樣本當中有100個樣本,每個樣本有兩個特徵:X1和X2.

3.1 用梯度上升法尋找最優參數


def getData():
    dataMat = []
    labels=[]
    fr = open('data/Ch05/testSet.txt')
    for line in fr.readlines():
        linearr=line.split()
        dataMat.append([1.0,float(linearr[0]),float(linearr[1])])
        labels.append(float(linearr[2]))
    return dataMat,labels
def sigmod(intX):
    result = []
    for x in intX:
    	result.append( 1.0/(1+exp(-1.0*x)))
    return result
def gradAscent(dataMatIn, classLabels):
    dataMatrix = mat(dataMatIn)             #convert to NumPy matrix
    labelMat = mat(classLabels).transpose() #convert to NumPy matrix
    m,n = shape(dataMatrix)
    alpha = 0.001
    maxCycles = 500
    weights = ones((n,1))
    for k in range(maxCycles):              #heavy on matrix operations
        h = sigmoid(dataMatrix*weights)     #matrix mult
        error = (labelMat - h)              #vector subtraction
        weights = weights + alpha * dataMatrix.transpose()* error #matrix mult
    return weights
def plotBestFit(weights):
    import matplotlib.pyplot as plt
    dataMat,labels=getData()
    dataArr = array(dataMat)
    n = shape(dataMat)[0]
    xcord1=[];ycord1=[]
    xcord2=[];ycord2=[]
    for i in range(n):
        if int(labels[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)
    plt.scatter(xcord1,ycord1,s=30,c='red',marker='s')
    plt.scatter(xcord2,ycord2,s=30,c='green')
    x=arange(-3.0,3.0,0.1)
    weights=array(weights)
    y=(-1*weights[0]-weights[1]*x)/weights[2]
    y=array(y)
    plt.plot(x,y)
    plt.xlabel('X1')
    plt.ylabel('X2')
    plt.show()


3.2 用隨機梯度上升法尋找最優參數

def getData():
    dataMat = []
    labels=[]
    fr = open('data/Ch05/testSet.txt')
    for line in fr.readlines():
        linearr=line.split()
        dataMat.append([1.0,float(linearr[0]),float(linearr[1])])
        labels.append(float(linearr[2]))
    return dataMat,labels
def sigmod(intX):
    result=1.0/(1+exp(-1.0*intX))
    return result
def gradAscent(dataMatIn, classLabels):
    dataMatrix = mat(dataMatIn)             #convert to NumPy matrix
    labelMat = mat(classLabels).transpose() #convert to NumPy matrix
    m,n = shape(dataMatrix)
    alpha = 0.001
    maxCycles = 500
    weights = ones((n,1))
    for k in range(maxCycles):              #heavy on matrix operations
        h = sigmoid(dataMatrix*weights)     #matrix mult
        error = (labelMat - h)              #vector subtraction
        weights = weights + alpha * dataMatrix.transpose()* error #matrix mult
    return weights
def stocGradAscent0(dataMatrix, classLabels):
    m,n = shape(dataMatrix)
    alpha = 0.01
    weights = ones(n)   #initialize to all ones
    for i in range(m):
        h = sigmoid(sum(dataMatrix[i]*weights))
        error = classLabels[i] - h
        weights = weights + alpha * error * dataMatrix[i]
    return weights
def plotBestFit(weights):
    import matplotlib.pyplot as plt
    dataMat,labels=getData()
    dataArr = array(dataMat)
    n = shape(dataMat)[0]
    xcord1=[];ycord1=[]
    xcord2=[];ycord2=[]
    for i in range(n):
        if int(labels[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)
    plt.scatter(xcord1,ycord1,s=30,c='red',marker='s')
    plt.scatter(xcord2,ycord2,s=30,c='green')
    x=arange(-3.0,3.0,0.1)
    weights=array(weights)
    y=(-1*weights[0]-weights[1]*x)/weights[2]
    y=array(y)
    plt.plot(x,y)
    plt.xlabel('X1')
    plt.ylabel('X2')
    plt.show()


3.3 用改進的隨機梯度上升法尋找最優參數

由於隨機訓練樣本比較少,所以用隨機梯度上升法求解結果較差,可以多運行幾次隨機梯度上升法同樣可以得到很好的結果。

def getData():
    dataMat = []
    labels=[]
    fr = open('data/Ch05/testSet.txt')
    for line in fr.readlines():
        linearr=line.split()
        dataMat.append([1.0,float(linearr[0]),float(linearr[1])])
        labels.append(float(linearr[2]))
    return dataMat,labels
def sigmod(intX):
    if(intX>100):return 1.0
    if(intX<-100):return 0.0
    result =  1.0/(1+exp(-1.0*intX))
    return result
def plotBestFit(weights):
    import matplotlib.pyplot as plt
    dataMat,labels=getData()
    dataArr = array(dataMat)
    n = shape(dataMat)[0]
    xcord1=[];ycord1=[]
    xcord2=[];ycord2=[]
    for i in range(n):
        if int(labels[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)
    plt.scatter(xcord1,ycord1,s=30,c='red',marker='s')
    plt.scatter(xcord2,ycord2,s=30,c='green')
    x=arange(-3.0,3.0,0.1)
    weights=array(weights)
    y=(-1*weights[0]-weights[1]*x)/weights[2]
    y=array(y)
    plt.plot(x,y)
    plt.xlabel('X1')
    plt.ylabel('X2')
    plt.show()
def stocGradAscent(dataMatrix,classLabels,numIter=150):
    m,n=shape(dataMatrix)
    weights=ones(n)
    dataIndex =list(range(m))
    for j in range(numIter):
        for i in range(m):
            alpha = 4/(1.0+i+j)+0.01
            randIndex = int(random.uniform(0,len(dataIndex)))
            h = sigmod(sum(dataMatrix[randIndex]*weights))
            error = float(classLabels[randIndex])-h
            weights=weights + alpha*error*dataMatrix[randIndex]
    return weights




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