三、迴歸——logistic迴歸二分類的python實現

一、訓練算法:使用梯度上升找到最佳參數

1.使用Logistic迴歸梯度上升優化算法

       每次更新迴歸係數都要遍歷整個數據集,該算法在處理100左右各樣本時還可以,但是如果有數十億樣本或者成千上萬的特徵,那麼該算法就太過於複雜了。

import os
from numpy import *

os.chdir("E:\python learning\Machine Learning in Action\machinelearninginaction\Ch05")  #設置路徑
#打開文件並逐行讀取,每行的前兩個值是特徵值X1,X2,第3列是數據對應的標籤
def loadDataSet():
    dataMat = []; labelMat = []
    fr = open('testSet.txt')
    for line in fr.readlines():
        lineArr = line.strip().split()  #去掉頭尾的空格,並以空白字符爲分隔符進行分割
        dataMat.append([1.0, float(lineArr[0]), float(lineArr[1])])   #並將dataMat矩陣的第一列設置爲1
        labelMat.append(int(lineArr[2]))
    return dataMat,labelMat   #輸出特徵矩陣和標籤矩陣
dataArr,labelMat = loadDataSet()
#定義sigmoid函數
def sigmoid(inX):
    return 1.0/(1+exp(-inX))

#定義梯度上升算法函數,其中dataMatIn參數爲2維numpy數組,每列代表不同的特徵,每行代表一個訓練樣本,labelMat爲標籤分類
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))   #n爲矩陣dataMatIn的列數,也就是變量的個數
    for k in range(maxCycles):              #heavy on matrix operations
        h = sigmoid(dataMatrix*weights)     #matrix mult,計算z值
        error = (labelMat - h)              #vector subtraction,計算預測值域實際值的偏差
        weights = weights + alpha * dataMatrix.transpose()* error #matrix mult  #梯度下降算法,找出最佳的參數
    return weights

#計算參數
weights = gradAscent(dataArr,labelMat)

2.分析數據:畫出決策邊界

#畫出決策邊界:畫出數據集和logistic迴歸最佳擬合直線的函數
def plotBestFit(wei):
    import matplotlib.pyplot as plt
    dataMat,labelMat=loadDataSet()  #導入數據
    dataArr = array(dataMat)        #dataMat轉換爲數組
    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 = (-wei[0]-wei[1]*x)/wei[2]
    ax.plot(x, y)
    plt.xlabel('X1'); plt.ylabel('X2');
    plt.show()

plotBestFit(weights.getA())

最後的分類結果如下,從圖中看只錯分了兩到四個點,但是這個例子所需要的計算量非常大,下面會對這一算法進行改進。

二、訓練算法:隨機梯度上升

      由於梯度上升算法只適合100左右各樣本的數據集的計算,在樣本量大時該方法就會變得太過於複雜。一種改進的方法就是一次只使用一個樣本點來更新迴歸係數,該方法就稱爲隨機梯度上升算法。由於隨機梯度上升算法可以在新樣本點到來時對分類器進行增量式更新,因此隨機梯度上升是一個在線學習的算法。與“在線學習”相對應的是一次性處理所有樣本,稱爲“批處理”。

隨機梯度上升算法可以寫成以下的僞代碼:

所有迴歸係數初始化爲1

對數據集中每個樣本

                計算該樣本的梯度

                使用alpha * gradient更新迴歸係數值

返回迴歸係數值

1.隨機梯度上升算法

#隨機梯度上升算法沒有矩陣的轉換過程,所有變量的數據類型都是Numpy數組。前面的梯度上升算法有矩陣的轉換過程
#隨機梯度上升算法的變量h和誤差error都是數值,梯度上升算法的爲向量
def stocGradAscent0(dataMatrix, classLabels):
    m,n = shape(dataMatrix)  #計算數組的形狀
    alpha = 0.01
    weights = ones(n)   #initialize to all ones
    for i in range(m):  #m爲樣本量
        h = sigmoid(sum(dataMatrix[i]*weights))   #每次值計算一個樣本點
        error = classLabels[i] - h
        weights = weights + alpha * error * dataMatrix[i]
    return weights

dataArr,labelMat = loadDataSet()
weights1 = stocGradAscent0(array(dataArr),labelMat)
plotBestFit(weights1)

2.改進的隨機梯度上升算法

(1)改進一:alpha在每次迭代中都會調整,在一定程度上可以緩解數據波動或高頻波動,雖然alpha會隨每次迭代次數不斷減小,但是永遠不會減小到0,必須這樣做的原因是爲了保證在多次迭代之後新數據仍然具有一定的影響,如果要處理的問題是動態變化的,name可以適當加上常數項,來確保新的值可以獲得更大的迴歸係數

(2)改進二:這裏通過隨機選取樣本來更新迴歸係數,這種方法將減少週期性的波動。

def stocGradAscent1(dataMatrix, classLabels, numIter=150):
    m,n = shape(dataMatrix)
    weights = ones(n)   #initialize to all ones
    for j in range(numIter):   #增加迭代次數
        dataIndex = list(range(m))     #這裏應該修改
        for i in range(m):
            alpha = 4/(1.0+j+i)+0.0001    #alpha在每次迭代中都會減小,但是不會爲0,這樣保證在多次迭代之後新數據仍然對參數有影響
            randIndex = int(random.uniform(0,len(dataIndex))) #隨機抽取樣本來更新參數
            h = sigmoid(sum(dataMatrix[randIndex]*weights))
            error = classLabels[randIndex] - h
            weights = weights + alpha * error * dataMatrix[randIndex]
            del(dataIndex[randIndex])
    return weights

dataArr,labelMat = loadDataSet()
weights2 = stocGradAscent1(array(dataArr),labelMat)
plotBestFit(weights2)

#默認的迭代次數是150次,可以更改爲500
weights3 = stocGradAscent1(array(dataArr),labelMat,500)
plotBestFit(weights3)

默認的迭代次數是150次,這裏可以更改爲500次來看效果

三、示例:從疝氣病症預測病馬的死亡率

1.使用logistic迴歸估計馬疝病的死亡率(從疝氣病症預測病馬的死亡率).步驟:

(1)收集數據:給定數據文件
(2)準備數據:用python解析文本文件並填充缺失值
(3)分析數據:可視化並觀察數據
(4)訓練算法:使用優化算法,找到最佳的系統
(5)測試算法:爲了量化迴歸的效果,需要觀察錯誤率。根據錯誤率決定是否回退到訓練階段,通過改變迭代的次數和步長等參數來得到更好的迴歸係數

(6)使用算法:實現一個簡單的命令行程序來收集馬的症狀並輸出預測結果。

2.代碼實現:

#classifyVector的第一個參數爲迴歸係數,weight爲特徵向量,這裏將輸入這兩個參數來計算sigmoid值,如果只大於0.5,則返回1,否則返回0.
def classifyVector(inX, weights):
    prob = sigmoid(sum(inX*weights))
    if prob > 0.5: return 1.0    #如果不想得到分類,則直接返回prob概率
    else: return 0.0

#打開數據集並對數據集進行處理
def colicTest():
    frTrain = open('horseColicTraining.txt'); frTest = open('horseColicTest.txt')
    trainingSet = []; trainingLabels = []
    
    #獲取訓練集的數據,並將其存放在list中
    for line in frTrain.readlines():
        currLine = line.strip().split('\t')
        lineArr =[]            #用於存放每一行的數據
        for i in range(21):    #這裏的range(21)是爲了循環每一列的值,總共有22列
            lineArr.append(float(currLine[i]))
        trainingSet.append(lineArr)
        trainingLabels.append(float(currLine[21]))    
    trainWeights = stocGradAscent1(array(trainingSet), trainingLabels, 1000)   #用改進的隨機梯度算法計算迴歸係數
   
    #計算測試集的錯誤率
    errorCount = 0; numTestVec = 0.0
    for line in frTest.readlines():
        numTestVec += 1.0
        currLine = line.strip().split('\t')
        lineArr =[]
        for i in range(21):
            lineArr.append(float(currLine[i]))
            #如果預測值和實際值不相同,則令錯誤個數加1
        if int(classifyVector(array(lineArr), trainWeights))!= int(currLine[21]):
            errorCount += 1
    errorRate = (float(errorCount)/numTestVec)    #最後計算總的錯誤率
    print ("the error rate of this test is: %f" % errorRate)
    return errorRate

#調用coicTest函數10次並求平均值
def multiTest():
    numTests = 10; errorSum=0.0
    for k in range(numTests):
        errorSum += colicTest()
    print ("after %d iterations the average error rate is: %f" % (numTests, errorSum/float(numTests)))

multiTest()

返回值如下:
multiTest()
__main__:2: RuntimeWarning: overflow encountered in exp
the error rate of this test is: 0.358209
the error rate of this test is: 0.313433
the error rate of this test is: 0.417910
the error rate of this test is: 0.358209
the error rate of this test is: 0.373134
the error rate of this test is: 0.328358
the error rate of this test is: 0.328358
the error rate of this test is: 0.298507
the error rate of this test is: 0.343284
the error rate of this test is: 0.328358

after 10 iterations the average error rate is: 0.344776

源數據下載:https://download.csdn.net/download/weixin_39541558/10467472

本文爲作者原創,如要轉載,請註明出處,謝謝!!

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