機(jī)器學(xué)習(xí)——邏輯回歸

邏輯回歸(Logistic Regression)

概述

假設(shè)現(xiàn)在有一些數(shù)據(jù)點(diǎn)缘琅,用一條直線對(duì)這些點(diǎn)進(jìn)行擬合(該線稱(chēng)為最佳擬合直線),這個(gè)擬合過(guò)程就稱(chēng)為回歸肘迎。
利用邏輯回歸進(jìn)行分類(lèi)的主要思想是:根據(jù)現(xiàn)有數(shù)據(jù)對(duì)分類(lèi)邊界線建立回歸公式甥温,以此進(jìn)行分類(lèi)。

算法流程

收集數(shù)據(jù):采用任意方法收集數(shù)據(jù)
準(zhǔn)備數(shù)據(jù):由于需要進(jìn)行距離計(jì)算妓布,因此要求數(shù)據(jù)類(lèi)型為數(shù)值型姻蚓。另外,結(jié)構(gòu)化數(shù)據(jù)格式則最佳
分析數(shù)據(jù):采用任意方法對(duì)數(shù)據(jù)進(jìn)行分析
訓(xùn)練算法:大部分時(shí)間將用于訓(xùn)練匣沼,訓(xùn)練的目的是為了找到最佳的分類(lèi)回歸系數(shù)
測(cè)試算法:一旦訓(xùn)練步驟完成狰挡,分類(lèi)將會(huì)很快
使用算法:首先,需要輸入一些數(shù)據(jù)释涛,并將其轉(zhuǎn)換成對(duì)應(yīng)的結(jié)構(gòu)化數(shù)值加叁;接著,基于訓(xùn)練好的回歸系數(shù)就可以對(duì)這些數(shù)值進(jìn)行簡(jiǎn)單的回歸計(jì)算唇撬,判定它們屬于哪個(gè)類(lèi)別它匕;在這之后,就可以在輸出的類(lèi)別上做一些其他分析工作

基于邏輯回歸和Sigmoid函數(shù)的分類(lèi)

邏輯回歸

優(yōu)點(diǎn):計(jì)算代價(jià)不高窖认,易于理解和實(shí)現(xiàn)
缺點(diǎn):容易欠擬合超凳,分類(lèi)精度可能不高
適用數(shù)據(jù)類(lèi)型:數(shù)值型和標(biāo)稱(chēng)型數(shù)據(jù)

我們想要的函數(shù)應(yīng)該是,能接受所有的輸入然后預(yù)測(cè)出類(lèi)別耀态。例如,對(duì)于而分類(lèi)問(wèn)題暂雹,該函數(shù)應(yīng)該返回0或1首装。具有這種性質(zhì)的函數(shù)稱(chēng)為海維塞德階躍函數(shù)(Heaviside step function),或直接稱(chēng)為單位階躍函數(shù)杭跪。海維塞德階躍函數(shù)的問(wèn)題在于:該函數(shù)在跳躍點(diǎn)上從0瞬間跳躍到1仙逻,這個(gè)瞬間跳躍過(guò)程有時(shí)很難處理驰吓。
Sigmoid函數(shù)是一個(gè)S型曲線,其函數(shù)形式為:
$$\sigma(z)=\frac{1}{1+e^{-z}}$$
當(dāng)輸入z等于0時(shí)系奉,Sigmoid函數(shù)值為0.5檬贰。隨著z的增大,對(duì)應(yīng)的函數(shù)值趨近于1缺亮;隨著z的減小翁涤,對(duì)應(yīng)的函數(shù)值趨近于0。

基于最優(yōu)化方法的最佳回歸系數(shù)確定

訓(xùn)練算法:適用梯度上升找到最佳參數(shù)

梯度上升法基于的思想是:要找到某函數(shù)的最大值萌踱,最好的方法是沿著該函數(shù)的梯度方向探尋葵礼。
梯度上升法的偽代碼:

每個(gè)回歸系數(shù)初始化為1
重復(fù)R次:
    計(jì)算整個(gè)數(shù)據(jù)集的梯度
    適用alpha x gradient 更新回歸系數(shù)的向量
返回回歸系數(shù)
import numpy as np

def loadDataSet():
    '''
    加載數(shù)據(jù)集
    '''
    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])])
        labelMat.append(int(lineArr[2]))
    return dataMat, labelMat

def sigmoid(inX):
    '''
    S函數(shù)
    '''
    return 1.0 / (1 + np.exp(-inX))

def gradAscent(dataMatIn, classLabels):
    '''
    梯度上升算法
    param dataMatIn: 特征值
    param classLabels: 標(biāo)簽
    '''
    # 特征值矩陣
    dataMatix = np.mat(dataMatIn)
    
    # 標(biāo)簽矩陣;行向量轉(zhuǎn)置為列向量
    labelMat = np.mat(classLabels).transpose()
    # 獲取特征值矩陣大小
    m, n = np.shape(dataMatix)
    # 移動(dòng)步長(zhǎng)
    alpha = 0.001
    # 迭代次數(shù)
    maxCycles = 500
    # 回歸系數(shù)初始化為1
    weights = np.ones((n, 1))
    
    for k in range(maxCycles):
        h = sigmoid(dataMatix * weights)
        error = (labelMat - h)
        weights = weights + alpha * dataMatix.transpose() * error
        
    return weights
dataArr, labelMat = loadDataSet()
weights = gradAscent(dataArr, labelMat)
weights
[out]
matrix([[ 4.12414349],
        [ 0.48007329],
        [-0.6168482 ]])

分析數(shù)據(jù):畫(huà)出決策邊界

def plotBestFit(weights):
    '''
    畫(huà)出數(shù)據(jù)集和邏輯回歸最佳擬合直線
    '''
    import matplotlib.pyplot as plt
    dataMat, labelMat = loadDataSet()
    dataArr = np.array(dataMat)
    n = np.shape(dataMat)[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 = np.arange(-3.0, 3.0, 0.1)
    y = (-weights[0]-weights[1]*x) / weights[2]
    ax.plot(x, y)
    plt.xlabel('X1')
    plt.ylabel('X2')
    plt.show()
plotBestFit(weights.getA())

訓(xùn)練算法:隨機(jī)梯度上升

梯度上升算法每次更新歸回系數(shù)時(shí)都需要遍歷整個(gè)數(shù)據(jù)集并鸵,數(shù)據(jù)量較小時(shí)尚可鸳粉,但如果有數(shù)十億樣本和上千萬(wàn)特征,那么該方法的計(jì)算復(fù)雜度就太高了园担。一種改進(jìn)方法是以此僅用一個(gè)樣本點(diǎn)來(lái)更新回歸系數(shù)届谈,該方法稱(chēng)為隨機(jī)梯度上升算法。由于可以在新樣本到來(lái)時(shí)對(duì)分類(lèi)器進(jìn)行增量式更新弯汰,因而隨機(jī)梯度上升算法是一個(gè)在線學(xué)習(xí)算法艰山。與“在線學(xué)習(xí)”相對(duì)應(yīng),一次處理所有數(shù)據(jù)被稱(chēng)作是“批處理”蝙泼。
隨機(jī)梯度算法偽代碼:

所有回歸系數(shù)初始化為1
對(duì)數(shù)據(jù)集中每個(gè)樣本
    計(jì)算該樣本的梯度
    適用 alpha x gradient 更新回歸系數(shù)值
返回回歸系數(shù)值
def stocGradAscent0(dataMatrix, classLabels):
    '''
    隨機(jī)梯度上升算法
    '''
    m, n = np.shape(dataMatrix)
    alpha = 0.01
    weights = np.ones(n)
    for i in range(m):
        h = sigmoid(sum(dataMatrix[i]*weights))
        error = classLabels[i] - h
        weights = weights + alpha * error * dataMatrix[i]
        
    return weights

測(cè)試隨機(jī)梯度上升算法
從結(jié)果上來(lái)看程剥,擬合出來(lái)的直線效果還不錯(cuò),但不像前面那么完美汤踏。這里的分類(lèi)器錯(cuò)分了三分之一的樣本织鲸。
但是前面的結(jié)果時(shí)迭代了500次才得到的。

dataArr, labelMat = loadDataSet()
weights = stocGradAscent0(np.array(dataArr), labelMat)
plotBestFit(weights)
image.png

對(duì)算法進(jìn)行改進(jìn)溪胶,增加迭代次數(shù)

import random

def stocGradAscent1(dataMatrix, classLabels, numIter=150):
    m, n = np.shape(dataMatrix)
    weights = np.ones(n)
    for j in range(numIter):
        dataIndex = range(m)
        for i in range(m):
            # 每次迭代時(shí)更新 alpha 值
            alpha = 4 / (1.0 + j + i) + 0.01
            # 隨機(jī)選取更新
            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

測(cè)試算法
發(fā)現(xiàn)經(jīng)過(guò)默認(rèn)150次迭代后搂擦,擬合直線與前面已經(jīng)差不多了。

dataArr, labelMat = loadDataSet()
weights = stocGradAscent1(np.array(dataArr), labelMat)
plotBestFit(weights)
image.png

示例:從疝氣病癥預(yù)測(cè)病馬的死亡率

使用邏輯回歸來(lái)預(yù)測(cè)患有疝氣病的馬的存活問(wèn)題哗脖。
測(cè)試集
訓(xùn)練集

收集數(shù)據(jù):給定數(shù)據(jù)文件瀑踢。
準(zhǔn)備數(shù)據(jù):用python解析文本文件并填充缺失值。
分析數(shù)據(jù):可視化并觀察數(shù)據(jù)才避。
訓(xùn)練算法:使用優(yōu)化算法橱夭,找到最佳的系數(shù)。
測(cè)試算法:為了量化回歸的效果桑逝,需要觀察錯(cuò)誤率棘劣。根據(jù)錯(cuò)誤率決定是否回退到訓(xùn)練階段,通過(guò)改變迭代的次數(shù)和步長(zhǎng)等參數(shù)來(lái)得到更好的回歸系數(shù)楞遏。
使用算法:實(shí)現(xiàn)一個(gè)簡(jiǎn)單的命令行程序來(lái)收集馬的癥狀

準(zhǔn)備數(shù)據(jù):處理缺失值

處理缺失值可選的做法:

使用可用特征的均值來(lái)填補(bǔ)缺失值
使用特殊值來(lái)填補(bǔ)缺失值茬暇,如-1
忽略有缺省值的樣本
使用相似樣本的均值填補(bǔ)缺失值
使用另外的機(jī)器學(xué)習(xí)算法預(yù)測(cè)缺失值

這里選擇實(shí)數(shù)0來(lái)替換所有缺失值首昔,因?yàn)槭褂肗umPy數(shù)據(jù)類(lèi)型不允許包含缺失值,而0恰好能適用于邏輯回歸糙俗±掌妫回歸系數(shù)的更新公式如下:
$weights = weights + alpha * error * dataMatrix[randindex]$
如果dataMatrix的某特征對(duì)應(yīng)值為0,那么該特征的系數(shù)不做更新巧骚,即:
$weights = weights$
另外赊颠,由于sigmoid(0) = 0.5,即它對(duì)結(jié)果的預(yù)測(cè)不具有任何傾向性网缝,因此選擇實(shí)數(shù)0作為缺失值也不會(huì)對(duì)誤差項(xiàng)造成影響巨税。

測(cè)試算法:用邏輯回歸進(jìn)行分類(lèi)

def classifyVector(inX, weights):
    '''
    邏輯回歸分類(lèi)函數(shù)
    parameter inX: 特征向量
    parameter weights: 回歸系數(shù)
    '''
    prob = sigmoid(sum(inX*weights))
    if prob > 0.5:
        return 1.0
    else:
        return 0.0
    
def colicTest():
    '''
    打開(kāi)測(cè)試集和訓(xùn)練集,并對(duì)數(shù)據(jù)進(jìn)行格式化處理
    '''
    frTrain = open('horseColicTraining.txt')
    frTest = open('horseColicTest.txt')
    trainingSet = []
    trainingLabels = []
    
    # 格式化訓(xùn)練集
    for line in frTrain.readlines():
        currLine = line.strip().split('\t')
        lineArr = []
        
        # 導(dǎo)入特征值粉臊,有21個(gè)特征
        for i in range(21):
            lineArr.append(float(currLine[i]))
        
        trainingSet.append(lineArr)
        # 導(dǎo)入類(lèi)別標(biāo)簽草添,類(lèi)別標(biāo)簽為最后一項(xiàng)
        trainingLabels.append(float(currLine[21]))
    
    # 使用隨機(jī)梯度上升算法計(jì)算回歸系數(shù)向量
    trainWeights = stocGradAscent1(np.array(trainingSet), trainingLabels, 500)
    errorCount = 0
    numTestVec = 0.0
    
    # 格式化測(cè)試集
    for line in frTest.readlines():
        numTestVec += 1.0
        currLine = line.strip().split('\t')
        lineArr = []
        
        # 導(dǎo)入特征值
        for i in range(21):
            lineArr.append(float(currLine[i]))
        
        # 使用訓(xùn)練集計(jì)算出的回歸系數(shù)對(duì)測(cè)試集進(jìn)行分類(lèi),并比對(duì)測(cè)試集的類(lèi)別標(biāo)簽扼仲,計(jì)算錯(cuò)誤數(shù)量
        if int(classifyVector(np.array(lineArr), trainWeights)) != int(currLine[21]):
            errorCount += 1
    
    # 錯(cuò)誤率
    errorRate = (float(errorCount)/numTestVec)
    print 'the error rate of this test is: %f' % errorRate
    
    return errorRate

def multiTest():
    '''
    調(diào)用colicTest函數(shù)10次远寸,取錯(cuò)誤率平均值
    '''
    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))

函數(shù)測(cè)試
10次迭代后,平均錯(cuò)誤率為35%屠凶。這個(gè)結(jié)果并不差驰后,因?yàn)橛?0%的缺失值。
如果調(diào)整colicTest()中的迭代次數(shù)和stocGradAscent1()中的步長(zhǎng)矗愧,平均錯(cuò)誤率還可以下降灶芝。

multiTest()
[out]
the error rate of this test is: 0.328358
the error rate of this test is: 0.358209
the error rate of this test is: 0.283582
the error rate of this test is: 0.313433
the error rate of this test is: 0.373134
the error rate of this test is: 0.373134
the error rate of this test is: 0.358209
the error rate of this test is: 0.343284
the error rate of this test is: 0.432836
the error rate of this test is: 0.388060
after 10 iterations the average error rate is: 0.355224

小結(jié)

邏輯回歸的目的是尋找一個(gè)非線性函數(shù)Signmoid的最佳擬合參數(shù),求解過(guò)程可以由最優(yōu)化算法來(lái)完成唉韭。在最優(yōu)化算法中夜涕,最常用的是梯度上升算法,而梯度上升算法又可以簡(jiǎn)化為隨機(jī)梯度上升算法属愤。
隨機(jī)梯度上升算法與梯度上升算法的效果相當(dāng)女器,但占用更少的計(jì)算機(jī)資源。此外住诸,隨機(jī)梯度上升算法是一個(gè)在線算法驾胆,它可以在新數(shù)據(jù)到來(lái)時(shí)完成參數(shù)更新,而不需要重新讀取整個(gè)數(shù)據(jù)集來(lái)進(jìn)行批處理運(yùn)算贱呐。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末丧诺,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子奄薇,更是在濱河造成了極大的恐慌锅必,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,978評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異搞隐,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)远搪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門(mén)劣纲,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人谁鳍,你說(shuō)我怎么就攤上這事癞季。” “怎么了倘潜?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,623評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵绷柒,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我涮因,道長(zhǎng)废睦,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,324評(píng)論 1 282
  • 正文 為了忘掉前任养泡,我火速辦了婚禮嗜湃,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘澜掩。我一直安慰自己购披,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,390評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布肩榕。 她就那樣靜靜地躺著刚陡,像睡著了一般。 火紅的嫁衣襯著肌膚如雪株汉。 梳的紋絲不亂的頭發(fā)上筐乳,一...
    開(kāi)封第一講書(shū)人閱讀 49,741評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音郎逃,去河邊找鬼哥童。 笑死,一個(gè)胖子當(dāng)著我的面吹牛褒翰,可吹牛的內(nèi)容都是我干的贮懈。 我是一名探鬼主播,決...
    沈念sama閱讀 38,892評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼优训,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼朵你!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起揣非,我...
    開(kāi)封第一講書(shū)人閱讀 37,655評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤抡医,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體忌傻,經(jīng)...
    沈念sama閱讀 44,104評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡大脉,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了水孩。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片镰矿。...
    茶點(diǎn)故事閱讀 38,569評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖俘种,靈堂內(nèi)的尸體忽然破棺而出秤标,到底是詐尸還是另有隱情,我是刑警寧澤宙刘,帶...
    沈念sama閱讀 34,254評(píng)論 4 328
  • 正文 年R本政府宣布苍姜,位于F島的核電站,受9級(jí)特大地震影響悬包,放射性物質(zhì)發(fā)生泄漏衙猪。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,834評(píng)論 3 312
  • 文/蒙蒙 一玉罐、第九天 我趴在偏房一處隱蔽的房頂上張望屈嗤。 院中可真熱鬧,春花似錦吊输、人聲如沸饶号。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,725評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)茫船。三九已至,卻和暖如春扭屁,著一層夾襖步出監(jiān)牢的瞬間算谈,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,950評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工料滥, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留然眼,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,260評(píng)論 2 360
  • 正文 我出身青樓葵腹,卻偏偏與公主長(zhǎng)得像高每,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子践宴,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,446評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容