天天看點

梯度下降法求解邏輯回歸_python實作邏輯回歸的計算邏輯使用python實作運作結果

文章目錄

  • 邏輯回歸的計算邏輯
  • 使用python實作
  • 運作結果

邏輯回歸是一種經典的二分類算法(當然也可以用作多分類),也是我們在進行資料分析和挖掘過程中最常使用的算法之一。

通常我們在選擇機器學習算法的時候,往往都是先選取簡單的模型,如邏輯回歸模型,因為它的原理簡單、可解釋性強,我們将簡單的模型和複雜的模型取得的結果進行對比,如果它們效果差不多,那我們也沒有必要選擇複雜的模型了,邏輯回歸就是這樣一種有效、易用的算法。

關于邏輯回歸的推導過程,學習資料有很多,這裡不再進行贅述。在這裡 我主要給大家梳理一下:①邏輯回歸算法的計算邏輯是怎麼樣的;②以及如何用python來子產品化實作這個流程。

邏輯回歸的計算邏輯

梯度下降法求解邏輯回歸_python實作邏輯回歸的計算邏輯使用python實作運作結果

邏輯回歸的計算邏輯可以用以上一張圖來表示。舉例來說,假設我們現在拿到一組樣本資料:exam1和exam2屬性代表兩門考試的成績,addimitted表示最終是否被錄取(1-錄取,0-未錄取),即每一行代表一個學生的兩門考試成績以及最終是否被錄取,現在要使用邏輯回歸算法來預測某學生最終是否能被錄取?

exam1 exam2 addimitted
34.623660 78.024693
30.286711 43.894998
35.847409 72.902198
60.182599 86.308552 1
79.032736 75.344376 1
…(100個樣本)

①首先我們要将原始資料分成X和y,用于後面的訓練,X包含exam1和exam2資料,y包含addimitt資料

②指定一個θ初始值以及學習率α,如果可以的話,還可以自己設定一個batchsize來選擇梯度下降的方法。

③計算損失函數和梯度值。

④判斷是否達到停止條件(如損失值的變化很小了、梯度值基本不再變化了、又或者達到了指定的疊代次數),如果達到了就傳回θ值,否則繼續疊代更新θ值。

以上就是邏輯回歸算法實作的基本思路。

使用python實作

以下是使用python實作以上算法流程時主要要完成的功能子產品,計算損失值、梯度值、進行參數更新等,除了這些主要子產品,還有停止政策等子產品沒有列出。

梯度下降法求解邏輯回歸_python實作邏輯回歸的計算邏輯使用python實作運作結果

代碼如下:

#加載相關的庫
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import numpy.random
import time
%matplotlib inline

#載入檔案
import os
path = 'data' + os.sep +'LogiReg_data.txt'
pdData = pd.read_csv(path, header = None, names = ['Exam 1','Exam 2', 'Admitted'])

#一、對資料預處理
#這裡主要是在資料最前面插入了數值全為1的列
pdData.insert(0, 'Ones', 1)
orig_data = pdData.as_matrix()
cols = orig_data.shape[1]
X = orig_data[:, 0:cols - 1]
y = orig_data[:, cols-1:cols]
theta = np.zeros([1,3])

#二、實作各個功能子產品
#①sigmoid函數轉換
def sigmoid(z):
    return 1/(1 + np.exp(-z))

#②輸入X和θ得到預測值
def model(X, theta):
    return sigmoid(np.dot(X, theta.T))

#③計算損失函數
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)

#④計算梯度
def gradient(X, y, theta):
    grad = np.zeros(theta.shape)
    error = (model(X, theta) - y).ravel()
    for j in range(len(theta.ravel())):
        term = np.multiply(error, X[:, j])
        grad[0, j] = np.sum(term) / len(X)
    return grad

#⑤設定停止政策
STOP_ITER = 0 #疊代次數為停止政策
STOP_COST = 1 #損失函數為停止政策
STOP_GRAD = 2 #梯度為停止政策
def stopCriterion(type, value, threshold):
    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

#⑥對資料進行洗牌
def shuffleData(data):
    np.random.shuffle(data)
    cols = data.shape[1]
    X = data[:, 0:cols-1]
    y = data[:, cols-1:]
    return X,y
   
#三、使用以上子產品定義梯度下降求解的函數
def descent(data, theta, batchSize, stopType, thresh, alpha):
    #梯度下降求解
    #batchSize參數指定了使用批量、随機還是小批量梯度下降
    #alpha是學習率
    
    init_time = time.time()
    i = 0 #疊代次數
    k = 0 #batch
    X, y = shuffleData(data)
    grad = np.zeros(theta.shape) #計算梯度
    costs = [cost(X, y, theta)] #損失值
    
    while True:
        grad = gradient(X[k:k+batchSize], y[k:k+batchSize], theta)
        k += batchSize #去batch數量個數倍
        if k >= n:
            k = 0
            X,y = shuffleData(data) #重新洗牌
        theta = theta - alpha * grad #參數更新
        costs.append(cost(X, y, theta))
        i += 1
        
        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
 
 #四、定義運作的函數,這裡主要是為了讓結果更加直覺,主要部分我們已經在上述步驟完成了
 def runExpe(data, theta, batchSize, stopType, thresh, alpha):
    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
           

運作結果

①采用随機梯度下降,設定學習率為0.001,疊代次數為5000次

可以看到損失函數沒有收斂的迹象,原因可能是學習率太大,或者疊代次數太少,是以調整學習率和疊代次數。

梯度下降法求解邏輯回歸_python實作邏輯回歸的計算邏輯使用python實作運作結果

②采用随機梯度下降,改變學習率為0.000002,疊代次數為15000次

可以看到損失函數存在波動,但是最終能夠收斂。

梯度下降法求解邏輯回歸_python實作邏輯回歸的計算邏輯使用python實作運作結果

随機梯度下降勝在速度快,但是穩定性差

③采用小批量梯度下降,批量為16,學習率為0.001,疊代次數為15000次

可以看損失函數波動很大,這裡可以嘗試對資料進行标準化。

梯度下降法求解邏輯回歸_python實作邏輯回歸的計算邏輯使用python實作運作結果

④采用小批量梯度下降,批量為16,學習率為0.001,疊代次數為15000次,但是對資料進行标準化

可以看損失函數能夠收斂了。是以,有一個原則:當我們得到的結果不太好,如發生浮動的時候,我們應該先從資料下手,看是否能對資料進行一系列改變之後能不能使得結果更好,先改資料、後改模型,這是基本思路!【資料預處理很重要】

梯度下降法求解邏輯回歸_python實作邏輯回歸的計算邏輯使用python實作運作結果

繼續閱讀