【ML從入門到入土系列02】線性迴歸與邏輯迴歸

1 線性迴歸

1.1 線性模型

線性模型是學習一個通過特徵的線性組合來進行預測的函數
其數學形式爲:f(x)=wTx+bf(\boldsymbol{x})=\boldsymbol{w}^{T} \boldsymbol{x}+b

1.2 定義

線性迴歸是採用線性模型解決迴歸問題,其輸出值爲連續型變量,實質是一種線性映射f(x)=θTxf(\mathbf{x})=\theta^{T} \mathbf{x}
在這裏插入圖片描述

1.3 損失函數

線性迴歸一般採用均方損失MSE,其公式如下:
J(θ0,θ1,,θn)=12mi=1m(hθ(x(i))y(i))2J\left(\theta_{0}, \theta_{1}, \ldots, \theta_{n}\right)=\frac{1}{2 m} \sum_{i=1}^{m}\left(h_{\theta}\left(x^{(i)}\right)-y^{(i)}\right)^{2}
其一階與二階函數的示意圖如下所示,顯然他們都是凸函數,便於後期採用梯度下降法優化。
在這裏插入圖片描述
在這裏插入圖片描述

1.4 梯度下降

梯度下降法即沿着loss梯度方向逐步修正參數,類似於下山,直至山底。

  • 一元
    θ1:=θ1αddθ1J(θ1)\theta_{1}:=\theta_{1}-\alpha \frac{d}{d \theta_{1}} J\left(\theta_{1}\right)
  • 二元
    θ0:=θ0α1mi=1m(hθ(x(i))y(i))θ1:=θ1α1mi=1m(hθ(x(i))y(i))x(i)\begin{array}{l} \theta_{0}:=\theta_{0}-\alpha \frac{1}{m} \sum_{i=1}^{m}\left(h_{\theta}\left(x^{(i)}\right)-y^{(i)}\right) \\ \theta_{1}:=\theta_{1}-\alpha \frac{1}{m} \sum_{i=1}^{m}\left(h_{\theta}\left(x^{(i)}\right)-y^{(i)}\right) \cdot x^{(i)} \end{array}
    其中,學習率設置十分重要,過大會振盪甚至不收斂,過小收斂速度會很慢。

1.5 過擬合與正則化

模型訓練經常遇到過擬合的情況,猶如模擬考出色,大考失敗。泛化能力差。一般採用正則化添加懲罰參數來解決。公式如下:
J(θ)=12m[i=1m(hθ(x(i))y(i))2+λj=1nθj2]J(\theta)=\frac{1}{2 m}\left[\sum_{i=1}^{m}\left(h_{\theta}\left(x^{(i)}\right)-y^{(i)}\right)^{2}+\lambda \sum_{j=1}^{n} \theta_{j}^{2}\right]

1.6 案例

線性迴歸預測城市入均收入情況。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
​
from sklearn.linear_model import LinearRegression
from mpl_toolkits.mplot3d import axes3d
​
pd.set_option('display.notebook_repr_html', False)
pd.set_option('display.max_columns', None)
pd.set_option('display.max_rows', 150)
pd.set_option('display.max_seq_items', None)
 
# 載入數據
data = np.loadtxt('linear_regression_data1.txt', delimiter=',')
​
X = np.c_[np.ones(data.shape[0]),data[:,0]]
y = np.c_[data[:,1]]

# 數據可視化
plt.scatter(X[:,1], y, s=30, c='r', marker='x', linewidths=1)
plt.xlim(4,24)
plt.xlabel('Population of City in 10,000s')
plt.ylabel('Profit in $10,000s');

在這裏插入圖片描述

# loss
def computeCost(X, y, theta=[[0],[0]]):
    m = y.size
    J = 0
    h = X.dot(theta)
    J = 1.0/(2*m)*(np.sum(np.square(h-y))) # MSE 
    return J

# 梯度下降
def gradientDescent(X, y, theta=[[0],[0]], alpha=0.01, num_iters=1500):
    m = y.size
    J_history = np.zeros(num_iters)  
    for iter in np.arange(num_iters):
        h = X.dot(theta)
        theta = theta - alpha*(1.0/m)*(X.T.dot(h-y)) # 參數更新
        J_history[iter] = computeCost(X, y, theta)
    return(theta, J_history)

xx = np.arange(5,23)
yy = theta[0]+theta[1]*xx

# loss收斂圖(我的線性迴歸)
plt.scatter(X[:,1], y, s=30, c='r', marker='x', linewidths=1)
plt.plot(xx,yy, label='Linear regression (Gradient descent)')

# loss收斂圖(Scikit-learn) 
regr = LinearRegression()
regr.fit(X[:,1].reshape(-1,1), y.ravel())
plt.plot(xx, regr.intercept_+regr.coef_*xx, label='Linear regression (Scikit-learn GLM)')

plt.xlim(4,24)
plt.xlabel('Population of City in 10,000s')
plt.ylabel('Profit in $10,000s')
plt.legend(loc=4);

在這裏插入圖片描述

# 預測一下人口爲70000的城市的結果
print(theta.T.dot([1, 7])*10000)

[ 45342.45012945]

2 邏輯迴歸

2.1 定義

線性迴歸解決分類問題不魯棒,其決策邊界是線性的,太古板。邏輯迴歸應運而生。

2.2 決策邊界

邏輯迴歸的精髓就是確定決策邊界,可以是線性的邊界,也可以是非線性的。如下圖所示。前提是用sigmoid函數將數據壓縮到0-1之間,公式爲:y=11+ezy=\frac{1}{1+e^{-z}}

在這裏插入圖片描述

2.3 損失函數

一般不採用線性迴歸的MSE,因爲會存在非凸函數。一般採用二元交叉熵損失,公式如下:
cost(hθ(x),y)={log(hθ(x)) if y=1log(1hθ(x)) if y=0\operatorname{cost}\left(h_{\theta}(x), y\right)=\left\{\begin{aligned} -\log \left(h_{\theta}(x)\right) & \text { if } y=1 \\ -\log \left(1-h_{\theta}(x)\right) & \text { if } y=0 \end{aligned}\right.
爲了防止過擬合,增加了正則化項,最終損失函數公式如下:
J(θ)=[1mi=1my(i)loghθ(x(i))+(1y(i))log(1hθ(x(i)))+λ2mj=1nθj2J(\theta)=\left[-\frac{1}{m} \sum_{i=1}^{m} y^{(i)} \log h_{\theta}\left(x^{(i)}\right)+\left(1-y^{(i)}\right) \log \left(1-h_{\theta}\left(x^{(i)}\right) \right)+\frac{\lambda}{2 m} \sum_{j=1}^{n} \theta_{j}^{2}\right.

2.4 梯度下降

同線性迴歸一樣,在保證loss是凸函數的前提下,採用梯度下降法優化。公式如下:
θj:=θjαθjJ(θ)\theta_{j}:=\theta_{j}-\alpha \frac{\partial}{\partial \theta_{j}} J(\theta)

2.5 案例

import pandas as pd
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
from scipy.optimize import minimize
from sklearn.preprocessing import PolynomialFeatures

pd.set_option('display.notebook_repr_html', False)
pd.set_option('display.max_columns', None)
pd.set_option('display.max_rows', 150)
pd.set_option('display.max_seq_items', None)

# 繪圖函數
def plotData(data, label_x, label_y, label_pos, label_neg, axes=None):
    # 獲得正負樣本的下標
    neg = data[:,2] == 0
    pos = data[:,2] == 1
    
    if axes == None:
        axes = plt.gca()
    axes.scatter(data[pos][:,0], data[pos][:,1], marker='+', c='k', s=60, linewidth=2, label=label_pos)
    axes.scatter(data[neg][:,0], data[neg][:,1], c='y', s=60, label=label_neg)
    axes.set_xlabel(label_x)
    axes.set_ylabel(label_y)
    axes.legend(frameon= True, fancybox = True);
     
# 載入數據
data2 = np.loadtxt('data2.txt', ',')
X = data2[:,0:2]
y = np.c_[data2[:,2]]

# loss
def costFunctionReg(theta, reg, *args):
    m = y.size
    h = sigmoid(XX.dot(theta))
    J = -1.0*(1.0/m)*(np.log(h).T.dot(y)+np.log(1-h).T.dot(1-y)) + (reg/(2.0*m))*np.sum(np.square(theta[1:])) # 二元交叉熵loss
    if np.isnan(J[0]):
        return(np.inf)
    return(J[0])

# 梯度下降
def gradientReg(theta, reg, *args):
    m = y.size
    h = sigmoid(XX.dot(theta.reshape(-1,1))) # 激活函數
    grad = (1.0/m)*XX.T.dot(h-y) + (reg/m)*np.r_[[[0]],theta[1:].reshape(-1,1)]   
    return(grad.flatten())

# 最高6階多項式
poly = PolynomialFeatures(6)
XX = poly.fit_transform(data2[:,0:2])
initial_theta = np.zeros(XX.shape[1])
costFunctionReg(initial_theta, 1, XX, y)

fig, axes = plt.subplots(1,3, sharey = True, figsize=(17,5))
# 分別設置不同的正則化係數:0.0, 1.0, 100.0
for i, C in enumerate([0.0, 1.0, 100.0]):
    res2 = minimize(costFunctionReg, initial_theta, args=(C, XX, y), jac=gradientReg, options={'maxiter':3000})
    # 準確率
    accuracy = 100.0*sum(predict(res2.x, XX) == y.ravel())/y.size   
    # 可視化
    plotData(data2, 'Microchip Test 1', 'Microchip Test 2', 'y = 1', 'y = 0', axes.flatten()[i])
    # 畫出決策邊界
    x1_min, x1_max = X[:,0].min(), X[:,0].max(),
    x2_min, x2_max = X[:,1].min(), X[:,1].max(),
    xx1, xx2 = np.meshgrid(np.linspace(x1_min, x1_max), np.linspace(x2_min, x2_max))
    h = sigmoid(poly.fit_transform(np.c_[xx1.ravel(), xx2.ravel()]).dot(res2.x))
    h = h.reshape(xx1.shape)
    axes.flatten()[i].contour(xx1, xx2, h, [0.5], linewidths=1, colors='g');       
    axes.flatten()[i].set_title('Train accuracy {}% with Lambda = {}'.format(np.round(accuracy, decimals=2), C))

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章