機器學習實戰(一)—— 線性迴歸

heize19發表於2020-12-01


前言

本文是基於《機器學習實戰》和吳恩達的ML課程自己的總結,也包括作業程式碼的重寫和註釋。


一、線性迴歸

1.定義

線性迴歸假設特徵和結果滿足線性關係。每個特徵對結果的影響都可以通過特徵前的引數體現,且每個特徵變數可以先對映到一個函式,然後再參與線性計算。從而表達特徵與結果之間的非線性關係。

如果用 x 1 x_1 x1, x 2 x_2 x2 x n x_n xn描述特徵,就可以通過以下函式做出估計:
在這裡插入圖片描述
這裡的θ表示了每個特徵的重要性,如果令x0=1就可以用向量來表示此函式:
在這裡插入圖片描述
為了評估算出來的θ是否合適,我們用損失(錯誤)函式來描述擬合程度:
線性迴歸的loss函式

2.θ的計算

梯度下降

為了確定θ的值,用梯度下降來使函式向J(θ)也就是損失函式下降最快的方向走,從而求得全域性最小值。哪個點向上,我們就向反方向下坡,所以我們可以更新J(θ):
在這裡插入圖片描述
梯度下降的方法一般有:

  1. 批量梯度下降:在計算梯度下降的每一步時,都是基於完整的訓練集X的。且可以找到全域性最小值,只是用的時間比較長。
  2. 隨機梯度下降:每一步在訓練集中隨機選擇一個例項,且僅基於該例項來計算梯度,其在達到最小值之後也會不斷反彈,此時不斷降低學習率從而儘可能接近全域性最小值。
  3. 小批量梯度下降:在小批量的隨機例項集上計算梯度,在引數空間中更穩定,其在最終比隨機梯度下降更接近最小值,但其可能很難擺脫區域性最小值。

最小二乘法

也是確定θ的方法之一,將訓練特徵表示為X矩陣,結果表示為y向量,從而得出θ:
在這裡插入圖片描述

3.帶權重的線性迴歸

帶權重的線性迴歸加入了權重,此演算法是假設離要預測的特徵越近影響越大,越遠越小,從而可以應用於非引數學習。
在這裡插入圖片描述
其中 w ( i ) w^{(i)} w(i)符合公式:
在這裡插入圖片描述

二、邏輯迴歸

1.定義

一般來說迴歸不會被用於分類,因為迴歸是連續型模型,且受噪聲影響較大,如果必須使用,可以使用對數迴歸,即在特徵到結果的對映中加入了一層函式對映,先把特徵線性求和,然後使用函式g(z)做運維假設函式來預測,g(z)可以將連續值對映到0和1上。

此時的迴歸方程:
在這裡插入圖片描述
其中g(z):
在這裡插入圖片描述
所以就可以實現用迴歸來進行二值分類,假設二值迴歸符合伯努利分佈,即:

在這裡插入圖片描述

他的損失函式為:
在這裡插入圖片描述
其實與線性迴歸類似,只是將 θ T X ( i ) \theta^TX^{(i)} θTX(i)通過g(z)對映到 h θ ( x ( i ) ) h_\theta\left(x\left(i\right)\right) hθ(x(i))

2.Softmax迴歸

是將邏輯迴歸推廣到多分類問題,對於一個給定的例項x,Softmax迴歸首先計算出每個類k的分數 s k ( x ) s_k(x) sk(x),然後將這些分數應用softmax(歸一化)函式,從而估算出每個類的概率。

對於某個類k:
s k ( x ) = x T θ ( k ) s_k(x)=x^T\theta^{(k)} sk(x)=xTθ(k)

softmax函式:
p ^ k = e x p ( s k ( x ) ) / ∑ i = 1 k e x p ( s j ( x ) ) {\widehat p}_k=exp(s_k(x))/\sum_{i=1}^kexp(s_j(x)) p k=exp(sk(x))/i=1kexp(sj(x))

交叉熵

用於衡量一組估算出的類概率跟目標類的匹配程度。

下面給出交叉熵:
J ( ⊙ ) = − 1 / m ( ∑ i = 1 m ∑ k = 1 K y k ( i ) l o g ( p ^ k ( i ) ) ) J(\odot)=-1/m(\sum_{i=1}^m\sum_{k=1}^Ky_k^{(i)}l\mathrm{og}(\widehat p_k^{(i)})) J()=1/m(i=1mk=1Kyk(i)log(p k(i)))

也是softmax迴歸函式的成本函式。

下面給出類k的交叉熵梯度向量:
∇ θ ( k ) J ( ⊙ ) = 1 / m ( ∑ i = 1 m ( p ^ k    ( i ) − y k ( i ) ) x ( i ) ) \nabla_{\theta(k)}J(\odot)=1/m(\sum_{i=1}^m(\widehat p_{k\;}^{(i)}-y_k^{(i)})x^{(i)}) θ(k)J()=1/m(i=1m(p k(i)yk(i))x(i))

三、練習

用softmax進行批量梯度下降,實現提前停止法

1.資料匯入

from sklearn import datasets
iris = datasets.load_iris()
list(iris.keys())
#取data的2,3列,即為花瓣的長度和寬度來預測
X = iris["data"][:,(2,3)]
y = iris["target"]
#np.c_列結合,所有的x0=1
import numpy as np
X_with_bias = np.c_[np.ones([len(X),1]),X]
#打亂output方便複用
np.random.seed(2042)
#分成訓練集、驗證集、測試集
test_ratio = 0.2
validation_ratio = 0.2
total_size = len(X_with_bias)

test_size = int(total_size*test_ratio)
validation_size = int(total_size*validation_ratio)
train_size = total_size-test_size-validation_size

rnd_indices = np.random.permutation(total_size)#np.random.permutation()為0-total_size之間的序列進行隨機排序

X_train = X_with_bias[rnd_indices[:train_size]]
y_train = y[rnd_indices[:train_size]]
X_valid = X_with_bias[rnd_indices[train_size:-test_size]]
y_valid = y[rnd_indices[train_size:-test_size]]
X_test = X_with_bias[rnd_indices[-test_size:]]
y_test = y[rnd_indices[-test_size:]]
#onehot編碼,為了方便訓練softmax迴歸模型
def to_one_hot(y):
  n_classes = y.max() + 1
  m = len(y)
  Y_one_hot = np.zeros((m, n_classes))
  Y_one_hot[np.arange(m),y] = 1
  return Y_one_hot
Y_train_one_hot = to_one_hot(y_train)
Y_valid_one_hot = to_one_hot(y_valid)
Y_test_one_hot = to_one_hot(y_test)

2.定義softmax函式

def softmax(logits):
  exps = np.exp(logits)
  exp_sum = np.sum(exps, axis=1, keepdims=True)
  return exps/exp_sum

3.定義輸入輸出

#定義輸入輸出數量
n_inputs = X_train.shape[1] #兩個特徵及偏置項
n_outputs = len(np.unique(y_train)) #對應3種分類

4.訓練模型

#訓練softmax迴歸模型,加入l2正則化和停止標誌
eta = 0.1
n_iterations = 5001
m = len(X_train)
epsilon = 1e-7
alpha = 0.1 #正則化超引數
best_loss = np.infty

Theta = np.random.randn(n_inputs, n_outputs)

for iteration in range(n_iterations):
  logits = X_train.dot(Theta)
  Y_proba = softmax(logits)
  xentropy_loss = -np.mean(np.sum(Y_train_one_hot * np.log(Y_proba+epsilon), axis=1))
  l2_loss = 1/2 * np.sum(np.square(Theta[1:]))
  loss = xentropy_loss + alpha * l2_loss
  error = Y_proba - Y_train_one_hot
  gradients = 1/m * X_train.T.dot(error) + np.r_[np.zeros([1, n_outputs]), alpha*Theta[1:]]
  Theta = Theta - eta*gradients

  logits = X_valid.dot(Theta)
  Y_proba = softmax(logits)
  xentropy_loss = -np.mean(np.sum(Y_valid_one_hot * np.log(Y_proba+epsilon), axis=1))
  l2_loss = 1/2 * np.sum(np.square(Theta[1:]))
  loss = xentropy_loss + alpha * l2_loss
  if iteration%500 == 0:
    print(iteration, loss)
  if loss < best_loss:
    best_loss = loss
  else:
    print(iteration-1, best_loss)
    print(iteration, loss, "early stopping")
    break

在這裡插入圖片描述

5.驗證結果

#驗證
logits = X_valid.dot(Theta)
Y_proba = softmax(logits)
y_predict = np.argmax(Y_proba, axis=1)

accuracy_score = np.mean(y_predict == y_valid)
accuracy_score

等於1.0

#最後驗證在測試集上效果
logits = X_test.dot(Theta)
Y_proba = softmax(logits)
y_predict = np.argmax(Y_proba, axis=1)

accuracy_score = np.mean(y_predict == y_test)
accuracy_score

約等於0.93

相關文章