機(jī)器學(xué)習(xí)之邏輯回歸(純python實(shí)現(xiàn))

logistic回歸是一種廣義的線性回歸髓涯,通過構(gòu)造回歸函數(shù),利用機(jī)器學(xué)習(xí)來實(shí)現(xiàn)分類或者預(yù)測年叮。

原理

上一文簡單介紹了線性回歸具被,與邏輯回歸的原理是類似的。

  1. 預(yù)測函數(shù)(h)只损。該函數(shù)就是分類函數(shù)一姿,用來預(yù)測輸入數(shù)據(jù)的判斷結(jié)果七咧。過程非常關(guān)鍵,需要預(yù)測函數(shù)的“大概形式”叮叹, 比如是線性還是非線性的艾栋。
    本文參考機(jī)器學(xué)習(xí)實(shí)戰(zhàn)的相應(yīng)部分,看一下數(shù)據(jù)集蛉顽。
// 兩個(gè)特征
-0.017612   14.053064   0
-1.395634   4.662541    1
-0.752157   6.538620 0
-1.322371   7.152853    0
0.423363 11.054677   0
0.406704    7.067335    1
image.png

如上圖蝗砾,紅綠代表兩種不同的分類⌒可以預(yù)測分類函數(shù)大概是一條直線遥诉。

  1. Cost函數(shù)(損失函數(shù)):該函數(shù)預(yù)測的輸出h和訓(xùn)練數(shù)據(jù)類別y之間的偏差,(h-y)或者其他形式噪叙。綜合考慮所有訓(xùn)練數(shù)據(jù)的cost矮锈, 將其求和或者求平均,極為J函數(shù)睁蕾, 表示所有訓(xùn)練數(shù)據(jù)預(yù)測值和實(shí)際值的偏差苞笨。

  2. 顯然,J函數(shù)的值越小子眶,表示預(yù)測的函數(shù)越準(zhǔn)確(即h函數(shù)越準(zhǔn)確)瀑凝,因此需要找到J函數(shù)的最小值。有時(shí)需要用到梯度下降臭杰。

具體過程

構(gòu)造預(yù)測函數(shù)

邏輯回歸名為回歸粤咪,實(shí)際為分類,用于兩分類問題渴杆。
這里直接給出sigmoid函數(shù)寥枝。


image.png

image.png

接下來確定分類的邊界,上面有提到磁奖,該數(shù)據(jù)集需要一個(gè)線性的邊界囊拜。
不同數(shù)據(jù)需要不同的邊界。


image.png

確定了分類函數(shù)比搭,將其輸入記做z 冠跷,那么


image.png

向量x是特征變量, 是輸入數(shù)據(jù)。此數(shù)據(jù)有兩個(gè)特征身诺,可以表示為z = w0x0 + w1x1 + w2x2蜜托。w0是常數(shù)項(xiàng),需要構(gòu)造x0等于1(見后面代碼)霉赡。
向量W是回歸系數(shù)特征橄务,T表示為列向量。
之后就是確定最佳回歸系數(shù)w(w0, w1, w2)同廉。

cost函數(shù)

綜合以上仪糖,預(yù)測函數(shù)為:

image.png

image.png

這里不做推導(dǎo)柑司,可以參考文章 Logistic回歸總結(jié)

image.png

有了上述的cost函數(shù)迫肖,可以使用梯度上升法求函數(shù)J的最小值锅劝。推導(dǎo)見上述鏈接。

綜上:梯度更新公式如下:


image.png

接下來是python代碼實(shí)現(xiàn):

# sigmoid函數(shù)和初始化數(shù)據(jù)
def sigmoid(z):
    return 1 / (1 + np.exp(-z))

def init_data():
    data = np.loadtxt('data.csv')
    dataMatIn = data[:, 0:-1]
    classLabels = data[:, -1]
    dataMatIn = np.insert(dataMatIn, 0, 1, axis=1)  #特征數(shù)據(jù)集蟆湖,添加1是構(gòu)造常數(shù)項(xiàng)x0
    return dataMatIn, classLabels
//  梯度上升
def grad_descent(dataMatIn, classLabels):
    dataMatrix = np.mat(dataMatIn)  #(m,n)
    labelMat = np.mat(classLabels).transpose()
    m, n = np.shape(dataMatrix)
    weights = np.ones((n, 1))  #初始化回歸系數(shù)(n, 1)
    alpha = 0.001 #步長
    maxCycle = 500  #最大循環(huán)次數(shù)

    for i in range(maxCycle):
        h = sigmoid(dataMatrix * weights)  #sigmoid 函數(shù)
        weights = weights + alpha * dataMatrix.transpose() * (labelMat - h)  #梯度
    return weights
// 計(jì)算結(jié)果
if __name__ == '__main__':
    dataMatIn, classLabels = init_data()
    r = grad_descent(dataMatIn, classLabels)
    print(r)

輸入如下:

[[ 4.12414349]
 [ 0.48007329]
 [-0.6168482 ]]

上述w就是所求的回歸系數(shù)故爵。w0 = 4.12414349, w1 = 0.4800, w2=-0.6168
之前預(yù)測的直線方程0 = w0x0 + w1x1 + w2x2, 帶入回歸系數(shù)隅津,可以確定邊界诬垂。
x2 = (-w0 - w1*x1) / w2

畫出函數(shù)圖像:

def plotBestFIt(weights):
    dataMatIn, classLabels = init_data()
    n = np.shape(dataMatIn)[0]
    xcord1 = []
    ycord1 = []
    xcord2 = []
    ycord2 = []
    for i in range(n):
        if classLabels[i] == 1:
            xcord1.append(dataMatIn[i][1])
            ycord1.append(dataMatIn[i][2])
        else:
            xcord2.append(dataMatIn[i][1])
            ycord2.append(dataMatIn[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, 3, 0.1)
    y = (-weights[0, 0] - weights[1, 0] * x) / weights[2, 0]  #matix
    ax.plot(x, y)
    plt.xlabel('X1')
    plt.ylabel('X2')
    plt.show()

如下:


image.png

算法改進(jìn)

隨機(jī)梯度上升

上述算法中,每次循環(huán)矩陣都會(huì)進(jìn)行m * n次乘法計(jì)算伦仍,時(shí)間復(fù)雜度是maxCycles* m * n结窘。當(dāng)數(shù)據(jù)量很大時(shí), 時(shí)間復(fù)雜度是很大充蓝。
這里嘗試使用隨機(jī)梯度上升法來進(jìn)行改進(jìn)隧枫。
隨機(jī)梯度上升法的思想是,每次只使用一個(gè)數(shù)據(jù)樣本點(diǎn)來更新回歸系數(shù)谓苟。這樣就大大減小計(jì)算開銷官脓。
算法如下:

def stoc_grad_ascent(dataMatIn, classLabels):
    m, n = np.shape(dataMatIn)
    alpha = 0.01
    weights = np.ones(n)
    for i in range(m):
        h = sigmoid(sum(dataMatIn[i] * weights))  #數(shù)值計(jì)算
        error = classLabels[i] - h
        weights = weights + alpha * error * dataMatIn[i]
    return weights

進(jìn)行測試:


image.png

隨機(jī)梯度上升的改進(jìn)

def stoc_grad_ascent_one(dataMatIn, classLabels, numIter=150):
    m, n = np.shape(dataMatIn)
    weights = np.ones(n)
    for j in range(numIter):
        dataIndex = list(range(m))
        for i in range(m):
            alpha = 4 / (1 + i + j) + 0.01 #保證多次迭代后新數(shù)據(jù)仍然有影響力
            randIndex = int(np.random.uniform(0, len(dataIndex)))
            h = sigmoid(sum(dataMatIn[i] * weights))  # 數(shù)值計(jì)算
            error = classLabels[i] - h
            weights = weights + alpha * error * dataMatIn[i]
            del(dataIndex[randIndex])
    return weights
image.png

可以對(duì)上述三種情況的回歸系數(shù)做個(gè)波動(dòng)圖。
可以發(fā)現(xiàn)第三種方法收斂更快涝焙。
評(píng)價(jià)算法優(yōu)劣勢看它是或否收斂卑笨,是否達(dá)到穩(wěn)定值,收斂越快仑撞,算法越優(yōu)赤兴。

總結(jié)

這里用到的梯度上升和梯度下降是一樣的,都是求函數(shù)的最值隧哮, 符號(hào)需要變一下搀缠。
梯度意味著分別沿著x, y的方向移動(dòng)一段距離近迁。(cost分別對(duì)x艺普, y)的導(dǎo)數(shù)。

完整代碼請查看:
github: logistic regression

參考文章:
機(jī)器學(xué)習(xí)之Logistic回歸與Python實(shí)現(xiàn)
機(jī)器學(xué)習(xí)筆記:Logistic回歸總結(jié)
機(jī)器學(xué)習(xí)基本算法系列之邏輯回歸

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末鉴竭,一起剝皮案震驚了整個(gè)濱河市歧譬,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌搏存,老刑警劉巖瑰步,帶你破解...
    沈念sama閱讀 222,252評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異璧眠,居然都是意外死亡缩焦,警方通過查閱死者的電腦和手機(jī)读虏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來袁滥,“玉大人盖桥,你說我怎么就攤上這事√夥” “怎么了揩徊?”我有些...
    開封第一講書人閱讀 168,814評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長嵌赠。 經(jīng)常有香客問我塑荒,道長,這世上最難降的妖魔是什么姜挺? 我笑而不...
    開封第一講書人閱讀 59,869評(píng)論 1 299
  • 正文 為了忘掉前任齿税,我火速辦了婚禮,結(jié)果婚禮上炊豪,老公的妹妹穿的比我還像新娘凌箕。我一直安慰自己,他們只是感情好溜在,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,888評(píng)論 6 398
  • 文/花漫 我一把揭開白布陌知。 她就那樣靜靜地躺著,像睡著了一般掖肋。 火紅的嫁衣襯著肌膚如雪仆葡。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,475評(píng)論 1 312
  • 那天志笼,我揣著相機(jī)與錄音沿盅,去河邊找鬼。 笑死纫溃,一個(gè)胖子當(dāng)著我的面吹牛腰涧,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播紊浩,決...
    沈念sama閱讀 41,010評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼窖铡,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了坊谁?” 一聲冷哼從身側(cè)響起费彼,我...
    開封第一講書人閱讀 39,924評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎口芍,沒想到半個(gè)月后箍铲,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,469評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鬓椭,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,552評(píng)論 3 342
  • 正文 我和宋清朗相戀三年颠猴,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了关划。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,680評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡翘瓮,死狀恐怖贮折,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情春畔,我是刑警寧澤脱货,帶...
    沈念sama閱讀 36,362評(píng)論 5 351
  • 正文 年R本政府宣布岛都,位于F島的核電站律姨,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏臼疫。R本人自食惡果不足惜择份,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,037評(píng)論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望烫堤。 院中可真熱鬧荣赶,春花似錦、人聲如沸鸽斟。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽富蓄。三九已至剩燥,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間立倍,已是汗流浹背灭红。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評(píng)論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留口注,地道東北人变擒。 一個(gè)月前我還...
    沈念sama閱讀 49,099評(píng)論 3 378
  • 正文 我出身青樓,卻偏偏與公主長得像寝志,于是被迫代替她去往敵國和親娇斑。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,691評(píng)論 2 361