文章目錄
- 一、前言
- 二、感覺機
- (1)那,什麼是感覺機呢?
- (2)感覺機的損失函數
- 點到直線的距離
- (3)随機梯度下降(Stochastic gradient descent,簡稱:SGD)
- 三、實戰
一、前言
邏輯回歸起源于線性回歸
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiI0gTMx81dsQWZ4lmZf1GLlpXazVmcvwFciV2dsQXYtJ3bm9CX9s2RkBnVHFmb1clWvB3MaVnRtp1XlBXe0xCMy81dvRWYoNHLwEzX5xCMx8FesU2cfdGLwMzX0xiRGZkRGZ0Xy9GbvNGLpZTY1EmMZVDUSFTU4VFRR9Fd4VGdsYTMfVmepNHLrJXYtJXZ0F2dvwVZnFWbp1zczV2YvJHctM3cv1Ce-cmbw5SO5UDN0EWYzEGM3MTM1ITNzYzX3QDO1UTMxIzLcBTMyIDMy8CXn9Gbi9CXzV2Zh1WavwVbvNmLvR3YxUjLyM3Lc9CX6MHc0RHaiojIsJye.png)
當資料點處于線性可分時,我們可以使用一條直線将其分開,而分割線的函數為:
那麼,怎樣判定這個資料點屬于哪一個類别呢?
可以通過函數進行劃分,比如:
sign
函數
那麼,當
(1)
和
(2)
組合起來,就成了感覺機,如:
二、感覺機
(1)那,什麼是感覺機呢?
線上性回歸的基礎上,将資料點進行劃分,并判定這個資料點屬于哪一個類别。
so,感覺機計算流程圖如下:
(2)感覺機的損失函數
如何減少誤分類情況呢?
通常會使用誤分類點到分割線(面)的距離去定義損失函數
點到直線的距離
對于 維實數向量空間中任意一點 到直線 的距離為:
其中 表示
然後,對于誤分類點
那麼,誤分類點 到分割線(面)的距離就為:
于是,假設所有誤分類點的集合為 ,全部誤分類點到分割線(面)的距離就為:
最後得到感覺機的損失函數為:
從公式(8)可以看出,損失函數 是非負的。也就是說,當沒有誤分類點時,損失函數的值為
0
。同時,誤分類點越少,誤分類點距離分割線(面)就越近,損失函數值就越小。同時,損失函數
(3)随機梯度下降(Stochastic gradient descent,簡稱:SGD)
影響因素:學習率太大或者疊代次數太少。
目的:為了快速極小化損失函數,增大“步長”,實作快速收斂。
- 一般梯度下降(Gradient descent):針對每個誤分類點執行梯度下降
- 随機梯度下降:每次随機選取一個誤分類點執行梯度下降
實驗 SGD 計算公式(8)的極小值時,首先任選一個分割面 和 ,然後使用梯度下降法不斷地極小化損失函數:
計算損失函數的偏導數:
如果 更新 和
實作代碼:
"""感覺機随機梯度下降算法實作
"""
def perceptron_sgd(X, Y, alpha, epochs):
"""
參數:
X -- 自變量資料矩陣
Y -- 因變量資料矩陣
alpha -- lamda 參數
epochs -- 疊代次數
傳回:
w -- 權重系數
b -- 截距項
"""
w = np.zeros(len(X[0])) # 初始化參數為 0
b = np.zeros(1)
for t in range(epochs): # 疊代
for i, x in enumerate(X):
if ((np.dot(X[i], w)+b)*Y[i]) <= 0: # 判斷條件
w = w + alpha*X[i]*Y[i] # 更新參數
b = b + alpha*Y[i]
return w,
三、實戰
// !wget -nc http://labfile.oss.aliyuncs.com/courses/1081/course-12-data.csv
"""加載資料集
"""
import pandas as pd
df = pd.read_csv("course-12-data.csv", header=0) # 加載資料集
df.head() # 預覽前 5 行資料
"""繪制資料集
"""
from matplotlib import pyplot as plt
%matplotlib inline
plt.figure(figsize=(10, 6))
plt.scatter(df['X0'],df['X1'], c=df['Y'])
// 求最佳分割線
import numpy as np
X = df[['X0','X1']].values
Y = df['Y'].values
alpha = 0.1
epochs = 150
perceptron_sgd(X, Y, alpha, epochs)
// 求解正确率
L = perceptron_sgd(X, Y, alpha, epochs)
w1 = L[0][0]
w2 = L[0][1]
b = L[1]
z = np.dot(X, np.array([w1, w2]).T) + b
np.sign(z)
// 也可使用sklearn 直接求得
from sklearn.metrics import accuracy_score
accuracy_score(Y, np.sign(z))
繪制決策邊界線
# 繪制輪廓線圖,不需要掌握
plt.figure(figsize=(10, 6))
plt.scatter(df['X0'],df['X1'], c=df['Y'])
x1_min, x1_max = df['X0'].min(), df['X0'].max(),
x2_min, x2_max = df['X1'].min(), df['X1'].max(),
xx1, xx2 = np.meshgrid(np.linspace(x1_min, x1_max), np.linspace(x2_min, x2_max))
grid = np.c_[xx1.ravel(), xx2.ravel()]
probs = (np.dot(grid, np.array([L[0][0], L[0][1]]).T) + L[1]).reshape(xx1.shape)
plt.contour(xx1, xx2, probs, [0], linewidths=1, colors='red');
繪制損失函數變換曲線
"""計算每次疊代後的損失函數值
"""
def perceptron_loss(X, Y, alpha, epochs):
"""
參數:
X -- 自變量資料矩陣
Y -- 因變量資料矩陣
alpha -- lamda 參數
epochs -- 疊代次數
傳回:
loss_list -- 每次疊代損失函數值清單
"""
w = np.zeros(len(X[0])) # 初始化參數為 0
b = np.zeros(1)
loss_list = []
for t in range(epochs): # 疊代
loss_init = 0
for i, x in enumerate(X):
if ((np.dot(X[i], w)+b)*Y[i]) <= 0: # 判斷條件
loss_init += (((np.dot(X[i], w)+b)*Y[i]))
w = w + alpha*X[i]*Y[i] # 更新參數
b = b + alpha*Y[i]
loss_list.append(loss_init * -1)
return loss_list
loss_list = perceptron_loss(X, Y, alpha, epochs)
plt.figure(figsize=(10, 6))
plt.plot([i for i in range(len(loss_list))], loss_list)
plt.xlabel("Learning rate {}, Epochs {}".format(alpha, epochs))
plt.ylabel("Loss function")
采取減國小習率 + 增加疊代次數的方法找到損失函數極小值點。
alpha = 0.05 # 減國小習率
epochs = 1000 # 增加疊代次數
loss_list = perceptron_loss(X, Y, alpha, epochs)
plt.figure(figsize=(10, 6))
plt.plot([i for i in range(len(loss_list))], loss_list)
plt.xlabel("Learning rate {}, Epochs {}".format(alpha, epochs))
plt.ylabel("Loss function")
L = perceptron_sgd(X, Y, alpha, epochs)
z = np.dot(X, L[0].T) + L[1]
accuracy_score(Y, np.sign(z))