python完整實(shí)現(xiàn)邏輯回歸

  1. 數(shù)據(jù)
    我們將建立一個(gè)邏輯回歸模型來(lái)預(yù)測(cè)一個(gè)學(xué)生是否被大學(xué)錄取。假設(shè)你是一個(gè)大學(xué)系的管理員线婚,你想根據(jù)兩次考試的結(jié)果來(lái)決定每個(gè)申請(qǐng)人的錄取機(jī)會(huì)嗅蔬。你有以前的申請(qǐng)人的歷史數(shù)據(jù),你可以用它作為邏輯回歸的訓(xùn)練集淌铐。對(duì)于每一個(gè)培訓(xùn)例子,你有兩個(gè)考試的申請(qǐng)人的分?jǐn)?shù)和錄取決定蔫缸。為了做到這一點(diǎn)腿准,我們將建立一個(gè)分類模型,根據(jù)考試成績(jī)估計(jì)入學(xué)概率捂龄。

  2. 導(dǎo)入數(shù)據(jù)并查看

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
import os
path = 'data' + os.sep + 'LogiReg_data.txt' # os.sep 根據(jù)你所處的平臺(tái)释涛,自動(dòng)地采用相應(yīng)的分割符號(hào)加叁。
pdData = pd.read_csv(path, header=None, names=['Exam 1', 'Exam 2', 'Admitted'])
pdData.head()
前5條數(shù)據(jù)
pdData.shape
數(shù)據(jù)量100行3列
positive = pdData[pdData['Admitted'] == 1] # 指定正例
negative = pdData[pdData['Admitted'] == 0] # 指定負(fù)例

fig, ax = plt.subplots(figsize=(10,5))
ax.scatter(positive['Exam 1'], positive['Exam 2'], s=30, c='b', marker='o', label='Admitted')
ax.scatter(negative['Exam 1'], negative['Exam 2'], s=30, c='r', marker='x', label='Not Admitted')
ax.legend()
ax.set_xlabel('Exam 1 Score')
ax.set_ylabel('Exam 2 Score')
數(shù)據(jù)分布情況
  1. 使用邏輯回歸


    算法實(shí)現(xiàn)步驟
  2. 先來(lái)建立sigmoid函數(shù)


def sigmoid(z):
    return 1 / (1 + np.exp(-z))
nums = np.arange(-10, 10, step=1) 
fig, ax = plt.subplots(figsize=(12,4))
ax.plot(nums, sigmoid(nums), 'r')
sigmoid
  1. model 返回預(yù)測(cè)結(jié)果
def model(X, theta): # 預(yù)測(cè)函數(shù)
    
    return sigmoid(np.dot(X, theta.T)) # 矩陣的乘法
需要設(shè)置的權(quán)重參數(shù)
pdData.insert(0, 'Ones', 1) # 新增一列值都為1
# set X (training data) and y (target variable)
orig_data = pdData.as_matrix() 
cols = orig_data.shape[1]
X = orig_data[:,0:cols-1]
y = orig_data[:,cols-1:cols]

# 轉(zhuǎn)換成numpy數(shù)組并插入?yún)?shù)數(shù)組
#X = np.matrix(X.values)
#y = np.matrix(data.iloc[:,3:4].values) #np.array(y.values)
theta = np.zeros([1, 3]) # 設(shè)置三個(gè)theta值

查看一下設(shè)置后的效果

X[:5]
y[:5]
theta
X.shape, y.shape, theta.shape

6 . 構(gòu)造損失函數(shù), 計(jì)算平均損失


def cost(X, y, theta):
    left = np.multiply(-y, np.log(model(X, theta)))
    right = np.multiply(1 - y, np.log(1 - model(X, theta)))
    return np.sum(left - right) / (len(X))
cost(X, y, theta) # 平均損失值
平均損失值
  1. 計(jì)算梯度


    求theta偏導(dǎo)
def gradient(X, y, theta):
    grad = np.zeros(theta.shape) # 有幾個(gè)theta就有幾個(gè)梯度
    error = (model(X, theta)- y).ravel()
    for j in range(len(theta.ravel())): #for each parmeter
        term = np.multiply(error, X[:,j])
        grad[0, j] = np.sum(term) / len(X)
    
    return grad

比較3種不同的梯度下降方法

STOP_ITER = 0
STOP_COST = 1
STOP_GRAD = 2

def stopCriterion(type, value, threshold):
    #設(shè)定三種不同的停止策略
    if type == STOP_ITER:        return value > threshold
    elif type == STOP_COST:      return abs(value[-1]-value[-2]) < threshold
    elif type == STOP_GRAD:      return np.linalg.norm(value) < threshold
import numpy.random
# 為了使模型的泛化能力更強(qiáng), 將數(shù)據(jù)全部打亂
def shuffleData(data):
    np.random.shuffle(data) # 洗牌函數(shù)
    cols = data.shape[1]
    X = data[:, 0:cols-1]
    y = data[:, cols-1:]
    return X, y
# 觀察時(shí)間對(duì)結(jié)果的影響
import time

def descent(data, theta, batchSize, stopType, thresh, alpha):
    #梯度下降求解
    
    init_time = time.time()
    i = 0 # 迭代次數(shù)
    k = 0 # batch
    X, y = shuffleData(data)
    grad = np.zeros(theta.shape) # 計(jì)算的梯度
    costs = [cost(X, y, theta)] # 損失值

    
    while True:
        grad = gradient(X[k:k+batchSize], y[k:k+batchSize], theta)
        k += batchSize #取batch數(shù)量個(gè)數(shù)據(jù)
        if k >= n: 
            k = 0 
            X, y = shuffleData(data) #重新洗牌
        theta = theta - alpha*grad # 參數(shù)更新
        costs.append(cost(X, y, theta)) # 計(jì)算新的損失
        i += 1 
        
        # 何時(shí)停止
        if stopType == STOP_ITER:       value = i
        elif stopType == STOP_COST:     value = costs
        elif stopType == STOP_GRAD:     value = grad
        if stopCriterion(stopType, value, thresh): break
    
    return theta, i-1, costs, grad, time.time() - init_time
#  根據(jù)傳入?yún)?shù)選擇梯度下降方式以及停止策略并繪圖展示
def runExpe(data, theta, batchSize, stopType, thresh, alpha):
    #import pdb; pdb.set_trace();
    theta, iter, costs, grad, dur = descent(data, theta, batchSize, stopType, thresh, alpha)
    name = "Original" if (data[:,1]>2).sum() > 1 else "Scaled"
    name += " data - learning rate: {} - ".format(alpha)
    if batchSize==n: strDescType = "Gradient"
    elif batchSize==1:  strDescType = "Stochastic"
    else: strDescType = "Mini-batch ({})".format(batchSize)
    name += strDescType + " descent - Stop: "
    if stopType == STOP_ITER: strStop = "{} iterations".format(thresh)
    elif stopType == STOP_COST: strStop = "costs change < {}".format(thresh)
    else: strStop = "gradient norm < {}".format(thresh)
    name += strStop
    print ("***{}\nTheta: {} - Iter: {} - Last cost: {:03.2f} - Duration: {:03.2f}s".format(
        name, theta, iter, costs[-1], dur))
    fig, ax = plt.subplots(figsize=(12,4))
    ax.plot(np.arange(len(costs)), costs, 'r')
    ax.set_xlabel('Iterations')
    ax.set_ylabel('Cost')
    ax.set_title(name.upper() + ' - Error vs. Iteration')
    return theta
  1. 比較不同的停止策略
  • 基于迭代次數(shù)停止
#選擇的梯度下降方法是基于所有樣本的
n=100
runExpe(orig_data, theta, n, STOP_ITER, thresh=5000, alpha=0.000001) # 迭代次數(shù)5000, 學(xué)習(xí)率0.0000001
基于迭代次數(shù)停止
  • 基于指定損失值停止
    設(shè)定閾值 1E-6, 差不多需要110 000次迭代
runExpe(orig_data, theta, n, STOP_COST, thresh=0.000001, alpha=0.001)
基于指定損失值停止
  • 基于梯度變化停止
    設(shè)定閾值 0.05,差不多需要40 000次迭代
runExpe(orig_data, theta, n, STOP_GRAD, thresh=0.05, alpha=0.001)
基于梯度變化停止
  1. 對(duì)比不同的梯度下降法
  • 隨機(jī)梯度下降法Stochastic descent
runExpe(orig_data, theta, 1, STOP_ITER, thresh=5000, alpha=0.001) # 每次迭代1個(gè)樣本

顯然很不穩(wěn)定, 試試將學(xué)習(xí)率調(diào)小一些

runExpe(orig_data, theta, 1, STOP_ITER, thresh=15000, alpha=0.000002)
調(diào)整學(xué)習(xí)率之后

由上圖可以看出速度快,但穩(wěn)定性差唇撬,需要很小的學(xué)習(xí)率

  • 小批量梯度下降法(Mini-batch Gradient Descent)
runExpe(orig_data, theta, 16, STOP_ITER, thresh=15000, alpha=0.001)

浮動(dòng)仍然比較大它匕,我們來(lái)嘗試下對(duì)數(shù)據(jù)進(jìn)行標(biāo)準(zhǔn)化 將數(shù)據(jù)按其屬性(按列進(jìn)行)減去其均值,然后除以其方差窖认。最后得到的結(jié)果是豫柬,對(duì)每個(gè)屬性/每列來(lái)說(shuō)所有數(shù)據(jù)都聚集在0附近,方差值為1

from sklearn import preprocessing as pp

scaled_data = orig_data.copy()
scaled_data[:, 1:3] = pp.scale(orig_data[:, 1:3])

runExpe(scaled_data, theta, n, STOP_ITER, thresh=5000, alpha=0.001)

它好多了扑浸!原始數(shù)據(jù)烧给,只能達(dá)到達(dá)到0.61,而我們得到了0.38個(gè)在這里喝噪! 所以對(duì)數(shù)據(jù)做預(yù)處理是非常重要的

runExpe(scaled_data, theta, n, STOP_GRAD, thresh=0.02, alpha=0.001)
更多的迭代次數(shù)會(huì)使得損失下降的更多础嫡!
theta = runExpe(scaled_data, theta, 1, STOP_GRAD, thresh=0.002/5, alpha=0.001)

隨機(jī)梯度下降更快,但是我們需要迭代的次數(shù)也需要更多酝惧,所以還是用batch的比較合適A穸Α!晚唇!

  • 最終使用mini-batch, 將批量值設(shè)為16
runExpe(scaled_data, theta, 16, STOP_GRAD, thresh=0.002*2, alpha=0.001)

只迭代了4000次, 損失值為0.21 得到了相對(duì)較好的效果

  1. 精度
#設(shè)定閾值
def predict(X, theta):
    return [1 if x >= 0.5 else 0 for x in model(X, theta)]

scaled_X = scaled_data[:, :3]
y = scaled_data[:, 3]
predictions = predict(scaled_X, theta)
correct = [1 if ((a == 1 and b == 1) or (a == 0 and b == 0)) else 0 for (a, b) in zip(predictions, y)]
accuracy = (sum(map(int, correct)) % len(correct))
print ('accuracy = {0}%'.format(accuracy))
轉(zhuǎn)換為概率值
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末巫财,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子哩陕,更是在濱河造成了極大的恐慌平项,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,331評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件悍及,死亡現(xiàn)場(chǎng)離奇詭異闽瓢,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)心赶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,372評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門(mén)鸳粉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人园担,你說(shuō)我怎么就攤上這事】菀梗” “怎么了弯汰?”我有些...
    開(kāi)封第一講書(shū)人閱讀 167,755評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)湖雹。 經(jīng)常有香客問(wèn)我咏闪,道長(zhǎng),這世上最難降的妖魔是什么摔吏? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,528評(píng)論 1 296
  • 正文 為了忘掉前任鸽嫂,我火速辦了婚禮纵装,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘据某。我一直安慰自己橡娄,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,526評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布癣籽。 她就那樣靜靜地躺著挽唉,像睡著了一般。 火紅的嫁衣襯著肌膚如雪筷狼。 梳的紋絲不亂的頭發(fā)上瓶籽,一...
    開(kāi)封第一講書(shū)人閱讀 52,166評(píng)論 1 308
  • 那天,我揣著相機(jī)與錄音埂材,去河邊找鬼塑顺。 笑死,一個(gè)胖子當(dāng)著我的面吹牛俏险,可吹牛的內(nèi)容都是我干的严拒。 我是一名探鬼主播,決...
    沈念sama閱讀 40,768評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼寡喝,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼糙俗!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起预鬓,我...
    開(kāi)封第一講書(shū)人閱讀 39,664評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤巧骚,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后格二,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體劈彪,經(jīng)...
    沈念sama閱讀 46,205評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,290評(píng)論 3 340
  • 正文 我和宋清朗相戀三年顶猜,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了沧奴。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,435評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡长窄,死狀恐怖滔吠,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情挠日,我是刑警寧澤疮绷,帶...
    沈念sama閱讀 36,126評(píng)論 5 349
  • 正文 年R本政府宣布,位于F島的核電站嚣潜,受9級(jí)特大地震影響冬骚,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,804評(píng)論 3 333
  • 文/蒙蒙 一只冻、第九天 我趴在偏房一處隱蔽的房頂上張望庇麦。 院中可真熱鬧,春花似錦喜德、人聲如沸山橄。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,276評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)驾胆。三九已至,卻和暖如春贱呐,著一層夾襖步出監(jiān)牢的瞬間丧诺,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,393評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工奄薇, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留驳阎,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,818評(píng)論 3 376
  • 正文 我出身青樓馁蒂,卻偏偏與公主長(zhǎng)得像呵晚,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子沫屡,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,442評(píng)論 2 359

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