Ng-機器學習(Day7)

SVM最大間距回顧:

  • 設SVM找到的決策邊界函數爲:f(x)=wTx+b(其中w就相當於Logistic迴歸當中的θ1、θ2…,b就是θ0)。當f(x)=0時就代表樣本點在決策邊界線上。如下圖所示當f(x)<-1時就是負樣本,f(x)>1時就是正樣本,因此可見f(x)描述了一個樣本點到決策邊界線上的距離。
    在這裏插入圖片描述

  • 爲什麼SVM被稱爲最大間距分類器呢?

  • 首先要搞清楚樣本點到決策邊界線f(x)=0的距離如何表示,上面我們已經談到了,f(x)可以用來表示樣本點到決策邊界線的距離。那麼要求間距也就時求min r (r=f(x)),也就是離決策邊界線最近的點到決策邊界線的距離。但是這樣時不合理的,因爲若等比的放大w和b,那麼f(x)也就會被等比的放大。

  • 假設有一個樣本點x,x0爲x做垂直於決策邊界線的直線的交點。r爲x到決策邊界線的距離,w爲垂直於決策邊界的向量。
    在這裏插入圖片描述

在這裏插入圖片描述

  • 有因爲我們的目標是尋找最大間距,所以問題就轉化爲了求max r’。有因爲有約束條件y(wTx+b)>1(即f(x)的絕對值大於1),所以問題就轉化爲了尋找最小的w。
  • 下面就可以看到支持向量機爲什麼又叫最大間隔分類器了。
  • 假設我們的決策邊界線爲下圖下左半部分的綠色線,此時我們的p(間距)是非常小的,那麼在約束條件下,我們要使得我們的θ(即w)足夠的大。這就和我們的目標相沖突了。
  • 如果我們是右邊的那條邊界,此時p(間距)就大多了,因此我們的θ就可以變小了,從而也就達到了我們本來的目標。這就是爲什麼要找最大間距。

在這裏插入圖片描述

尋找最優參數:

  • 首先讀取數據,繪製圖像
import numpy as np
import scipy.io as sio
import scipy.optimize as opt
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

def loadData():
    d = sio.loadmat('E:/Data/Ng/Coursera-ML-AndrewNg-Notes-master/code/ex5-bias vs variance/ex5data1.mat')
    return map(np.ravel,[d['X'],d['y'],d['Xval'],d['yval'],d['Xtest'],d['ytest']])

if __name__=='__main__':
	X, y, Xval, yval, Xtest, ytest = loadData()
	X,Xval,Xtest = [np.insert(x.reshape(x.shape[0],1),0,values = np.ones(x.shape[0]),axis=1) for x in (X,Xval,Xtest)] #批量加人爲全爲1的列
	plt.figure(figsize = (10,10),dpi=70)
    plt.scatter(X,y,s=20,color = 'red')
    plt.show()

在這裏插入圖片描述

  • 計算出最優θ
def cost(theta,X,y):
    m = X.shape[0]
    inner = X @theta - y #(12,1)
    square_sum = inner.T @inner
    cost = square_sum/(2*m)
    return cost

def regularize_cost(theta,X,y,l):
    m=X.shape[0]
    reg_term = np.power(theta[1:],2).sum()*(l/(2*m))
    return cost(theta,X,y)+reg_term

def gradient(theta,X,y):
    m=X.shape[0]
    inner = X.T @ (X @ theta - y)
    return inner/m

def regularize_gradient(theta,X,y,l=1):
    m=X.shape[0]
    theta_ = theta.copy()
    theta_[0]=0
    reg_term = theta_*(l/m)
    return reg_term + gradient(theta,X,y)

def linear_regression_np(X,y,l):
    m = X.shape[1]
    theta = np.ones(m)
    res = opt.minimize(fun=regularize_cost
                       ,x0=theta,args=(X,y,l)
                       ,method='TNC'
                       ,jac=regularize_gradient
                       ,options={'disp': True})
    return res

if __name__ == '__main__':
    theta = np.ones(X.shape[0])
    final_theta = linear_regression_np(X, y, l=0).get('x') 
    final_theta
    Y=final_theta[0]+final_theta[1]*X[:,1]
	#plt.figure(figsize=(10,10),dpi=70)
	plt.scatter(X[:,1],y,s=30,color='red')
	plt.plot(X[:,1],Y)
	plt.show()

結果如下:
在這裏插入圖片描述

可見擬合的不是很好
在這裏插入圖片描述

  • 畫出訓練集和交叉驗證集的代價函數曲線
training_cost = [] #初始化一個列表
cv_cost=[]
for i in range(1,X.shape[0]+1): #樣本量逐個增加
    res = linear_regression_np(X[:i,:], y[:i], l=0) #獲取最優θ
    
    train_cost = regularize_cost(res.x,X[:i,:],y[:i],l=0) #計算訓練集代價函數
    cvcost = regularize_cost(res.x,Xval,yval,l=0) #計算交叉驗證集訓練函數
    training_cost.append(train_cost)
    cv_cost.append(cvcost)
    
plt.plot(np.arange(11+1),training_cost,color='blue',label='training cost')
plt.plot(np.arange(11+1),cv_cost,color='red',label='cv cost')
plt.legend(loc=1)
plt.show()

結果如下:
從下圖可以看見,隨着樣本量的增加,交叉驗證集上的代價值不斷的下降,訓練集的代價函數不斷的上升。但是沒有相交,存在着一個空隙,即欠擬合。
在這裏插入圖片描述

  • 應對欠擬合,我們可以利用增加多項式;增加特徵數;降低lambda值的方式來應對。
    這裏我們使用的是增加高次項。
def poly_features(x,power,as_ndarray=False):
	df = {'f{}'.format(i): np.power(x,i)
		for i range(1,power+1)}
	df = pd.DataFrame(df)
	if as_ndarray:
		return np.array(df)
	else:
		return df

def normalize(data):
	return data.apply(lambda columns: (columns - columns.mean())/columns.std())

def prepare_poly_features(*args,power):
	"""用來咱批量增加高次項
	Params:
		args:訓練集/交叉驗證集/測試集
		power:最高次方
	return:
		處理完畢的數據"""
	def prepare(x,power):
		df = poly_features(x,power=power)
		df = normalize(df).values
		return np.insert(df,0,np.ones(df.shape[0]),axis=1)
	return [prepare(x) for x in args]

if __name__ == '__main__':
	X_,X_test,X_val = prepare_poly_data(X,Xtest,Xval,power=8)
	X_[:3,:]


結果爲:
在這裏插入圖片描述

  • 接下來重新繪製
def plot_learning_curve(X, y, Xval, yval, l=0):
    training_cost, cv_cost = [], []
    m = X.shape[0]

    for i in range(1, m + 1):
        # regularization applies here for fitting parameters
        res = linear_regression_np(X[:i, :], y[:i], l=l)

        # remember, when you compute the cost here, you are computing
        # non-regularized cost. Regularization is used to fit parameters only
        tc = cost(res.x, X[:i, :], y[:i])
        cv = cost(res.x, Xval, yval)

        training_cost.append(tc)
        cv_cost.append(cv)

    plt.plot(np.arange(1, m + 1), training_cost, label='training cost')
    plt.plot(np.arange(1, m + 1), cv_cost, label='cv cost')
    plt.legend(loc=1)

if __name___ == '__main__':
	plot_learning_curve(X_poly, y, Xval_poly, yval, l=0)
	plt.show()

可見訓練集的代價函數總爲1,不夠真實,那麼可能是過擬合了。
在這裏插入圖片描述

  • 嘗試λ=1
plot_learning_curve(X_poly, y, Xval_poly, yval, l=1)
plt.show()

訓練集的代價函數提高了一點,但是還是太低
在這裏插入圖片描述

  • 再試試λ=100
plot_learning_curve(X_poly, y, Xval_poly, yval, l=100)
plt.show()

這下欠擬合了
在這裏插入圖片描述

  • 找到最佳的λ:
l_candidate = [0, 0.001, 0.003, 0.01, 0.03, 0.1, 0.3, 1, 3, 10] #逐個嘗試
training_cost, cv_cost = [], []
for l in l_candidate:
    res = linear_regression_np(X_poly, y, l)
    
    tc = cost(res.x, X_poly, y)
    cv = cost(res.x, Xval_poly, yval)
    
    training_cost.append(tc)
    cv_cost.append(cv)

plt.plot(l_candidate, training_cost, label='training')
plt.plot(l_candidate, cv_cost, label='cross validation')
plt.legend(loc=2)

plt.xlabel('lambda')

plt.ylabel('cost')
plt.show()
l_candidate[np.argmin(cv_cost)] #找到交叉驗證集當中代價函數最小的那個λ的索引

在這裏插入圖片描述
在這裏插入圖片描述

  • 看看那個比較好
for l in l_candidate:
    theta = linear_regression_np(X_poly, y, l).x
    print('test cost(l={}) = {}'.format(l, cost(theta, Xtest_poly, ytest)))

可見λ=0.3時最小
在這裏插入圖片描述

總結:

尋找合適λ可以先試着畫幾個圖,然後再確定值來依此遍歷,然後找出使得代價函數最小的那個λ,然後再看測試集,找到測試集當中最小的λ。

參考資料:

  1. Ng機器學習
  2. 黃博筆記
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章