文章目錄
- 邏輯回歸的計算邏輯
- 使用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實作以上算法流程時主要要完成的功能子產品,計算損失值、梯度值、進行參數更新等,除了這些主要子產品,還有停止政策等子產品沒有列出。
代碼如下:
#加載相關的庫
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次
可以看到損失函數沒有收斂的迹象,原因可能是學習率太大,或者疊代次數太少,是以調整學習率和疊代次數。
②采用随機梯度下降,改變學習率為0.000002,疊代次數為15000次
可以看到損失函數存在波動,但是最終能夠收斂。
随機梯度下降勝在速度快,但是穩定性差
③采用小批量梯度下降,批量為16,學習率為0.001,疊代次數為15000次
可以看損失函數波動很大,這裡可以嘗試對資料進行标準化。
④采用小批量梯度下降,批量為16,學習率為0.001,疊代次數為15000次,但是對資料進行标準化
可以看損失函數能夠收斂了。是以,有一個原則:當我們得到的結果不太好,如發生浮動的時候,我們應該先從資料下手,看是否能對資料進行一系列改變之後能不能使得結果更好,先改資料、後改模型,這是基本思路!【資料預處理很重要】