Ng-機器學習(Day 3)

Logistic 多分類問題:

面對Logistic多分類問題,通常的分類是將一類單獨拎出來,然後其他剩下的分爲另一類。這樣就可以利用二元Logistic迴歸的思路了。

比如下圖,我們一共有三個類,那麼我們會有三個分類器,然後依此計算hypothesis函數的值,最後看那個類別下的h值最大,那麼就將其歸爲這一類。
在這裏插入圖片描述在這裏插入圖片描述

過擬合問題:

簡單來說,過擬合就是指一個模型在訓練集上表現的相當好(代價函數可能非常的接近於0 ),但是在測試集上的表現比較差,無法準確的進行預測。

下圖中,圖1:可見一元的線性方程無法較好的去擬合這個房價的模型(因爲,房價在隨着大小的增加越來越趨向於穩定,但是這個模型擬合的線是沒有表現出來穩定的趨勢的。),因此我們可以叫這種現象爲“欠擬合(Under fitting)”或“高偏差(High bias)”; 圖3 可以看到是一個高階的模型,它擬合出來的線是由很多上下波動的,這可以叫“過度擬合(Over fitting)”或“高方程”.
在這裏插入圖片描述

解決:

  1. 減少特徵數量
  2. 正則化
    概念:
    通過懲罰模型中參數的方法來,使得模型變的平滑。

看下圖的這個例子。
在這裏插入圖片描述
原來的模型當中theta_3,theta_4分別是x的三次和x的四次的參數。因爲高階的存在,會使得我們的模型變得彎彎扭扭。那麼我們如果希望這個模型和左邊的那個相似應該怎麼做呢?

那必然是要減少theta_3和theta_4對於模型的影響!減少到theta_3和theta_4幾乎等於0(就好像被這兩項被去掉了一樣,這樣我們就可以得到一個近似左圖的模型了。)

那麼怎麼做呢?

我們可以在後面添加兩項,如下圖。
在這裏插入圖片描述
因爲我們期望這個代價函數得到最小值,那麼我們肯定不希望前面係數爲1000的theta_3和theta_4大,而是要這兩個參數儘可能的小,從而我們的theta_3,和theta_4對於整個模型的影響就會減小,使我們得到一個比較平滑模型。

上面的例子當中,我們知道想要懲罰哪一項,但是當我們的特徵數量非常多的時候,我們往往無法知道我們需要懲罰哪些特徵項。

因此,利用正則化來縮小出來theta_0外的所有的參數
在這裏插入圖片描述

這裏的lambda就是正則化參數,它是用來控制兩個目標的取捨的。
第一個目標:更好的擬合數據
第二個目標:使得參數儘可能的小

在這裏插入圖片描述
注:當lambda過大,可能就會對所有的參數懲罰過大,最後就的h函數可能就成爲下面這樣了。。
在這裏插入圖片描述

線性迴歸正則化:

  • 梯度下降法:
    我們將上面討論到的正則化方法加入到梯度下降函數當中,那麼我們求偏導之後的結果就如下圖所示。
    其中alpha*(lamda/m)是一個很小很小的正數,所以說,每次更新一次參數,那麼我們的theta就會是原來的theta*比一小一點點的數,再減去後面的那項。
    在這裏插入圖片描述
  • 正規方程法:
    在原來的基礎上增加一個lambda*一個對角矩陣(假設矩陣爲A,那麼A11就是0,對角線其他值都爲1)
    在這裏插入圖片描述
    對於不可逆問題:
    利用正則化,只要保證lambda>0,那麼就可以使得矩陣可逆。
    在這裏插入圖片描述

Logistic 迴歸正則化:

  • 代價函數
    在這裏插入圖片描述
  • 梯度下降
    在這裏插入圖片描述

Logistic迴歸 正則化實例:

  • 首先讀取數據,查看數據分佈情況
import pandas as pd 
import numpy as np
from matplotlib import pyplot as plt 
import seaborn as sns
Data = pd.read_csv('E:/Data/Ng/Coursera-ML-AndrewNg-Notes-master/code/ex2-logistic regression/ex2data2.txt',names=['exam1','exam2','accepted'])
Data.head(30)

sns.set(context='notebook',style='ticks',font_scale = 1.5)
sns.lmplot('exam1','exam2',hue = 'accepted',data=Data,height = 6,fit_reg=False,scatter_kws={'s':50})
plt.title('Regularized Logistic Regression')
plt.show()

結果如下:
從散點分佈情況來看,這個條決策線應當是一個近似圓形的線才能分割。
在這裏插入圖片描述
在這裏插入圖片描述

  • 因爲目前讀取的數據最高只有一次項,所以要寫一個函數來進行轉化數據。
def feature_mapping(x,y,power,as_ndarray=False):
    """將函數轉化爲高階,把兩個特徵值轉化爲多個特徵值
    polynomial expansion法"""
    data = {'f{}{}'.format(i-p,p) : np.power(x,i-p)*np.power(y,p)
           for i in np.arange(power+1)
           for p in np.arange(i+1)}
    if as_ndarray:
        return np.array(pd.DataFrame(data))
    else:
        return pd.DataFrame(data)
x1 = np.array(Data['exam1'])
x2= np.array(Data['exam2'])
data = feature_mapping(x1,x2,power=6)
print(data.shape)
data.head()

注意根據兩個數值可以看出是幾次方:
f00:x10 * x20
f10: x11 * x20
f20: x12 * x20
所以根據輸入power值多少,就可以計算到幾次方,這樣就可以應用到我們的正則化當中的。
在這裏插入圖片描述

  • 定義必要的函數:

在這裏插入圖片描述

def get_y(Data):
    return np.array(Data.iloc[:,-1])

def sigmoid(z):
    return 1/(1+np.exp(-z))

在這裏插入圖片描述

def gradient(theta,x,y):
    return (1/len(x))* x.T@ (sigmoid(x@theta)-y)

在這裏插入圖片描述

def cost(theta, X, y):
    return np.mean(-y * np.log(sigmoid(X @ theta)) - (1 - y) * np.log(1 - sigmoid(X @ theta)))

在這裏插入圖片描述

def regcost(theta,x,y,l=1):
    m = len(x)
    theta_j1_jn = theta[1:] #首先新建一個theta函數,因爲theta0不需要處理,所以取出theta1到n即可
    regularized_term = (l/(2*m))* np.power(theta_j1_jn,2).sum() #根據公式計算出正則化項
    return cost(theta,x,y)+regularized_term

在這裏插入圖片描述

def reg_descent(theta,x,y,l=1):
    theta_j1_jn = theta[1:]
    regularized_theta = (l/len(x))*theta_j1_jn #正則化項
    regularized_term = np.concatenate([np.array([0]),regularized_theta]) #因爲theta_0不動,這時候要將其組合回去
    return gradient(theta,x,y) + regularized_term
  • 利用scipy.optimize的minimize來進行擬合
import scipy.optimize as ops
theta = np.zeros(data.shape[1])
X = feature_mapping(x1,x2,power=6,as_ndarray=True)
y = get_y(Data)
res = ops.minimize(fun = regcost,x0 = theta,args=(X,y),method='Newton-CG',jac=reg_descent)
res

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

  • 測試精確度
X = feature_mapping(x1,x2,power=6,as_ndarray=True)
y = get_y(Data)

res = ops.minimize(fun = regcost,x0 = theta,args=(X,y),method='Newton-CG',jac=reg_descent)

def pred_y(final_theta,x):
    prob = sigmoid(x@final_theta)
    test = []
    for each in prob:
        if each>0.5:
            test.append(1)
        else:
            test.append(0)
    return test

final_theta = res.x
pred = pred_y(final_theta,X)
print(classification_report(y,pred))

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

  • 繪製決策邊界:
def feature_mapped_logistic_regression(power,l):
	"""獲取最優擬合參數
	Params:
		power:函數最高次方
		l:lambda
	return:
		final_theta:最優擬合參數"""
    Data = pd.read_csv('E:/Data/Ng/Coursera-ML-AndrewNg-Notes-master/code/ex2-logistic regression/ex2data2.txt',names=['exam1','exam2','accepted'])
    x0 = np.array(Data['exam1'])
    x1 = np.array(Data['exam2'])
    y = get_y(Data)
    
    X = feature_mapping(x0,x1,power,as_ndarray=True) #獲取高次方函數
    theta = np.zeros(X.shape[1])
    res = ops.minimize(fun=regcost,x0=theta,args=(X,y,l),method='TNC',jac=reg_descent) 
    final_theta = res.x
    
    return final_theta

def find_decision_boundary(density, power, theta, threshhold):
	""""找到最合適的參數
	目前理解的不太清楚,希望知道的朋友可以留言告訴我一下,謝謝!"""
    t1 = np.linspace(-1, 1.5, density) #因爲我數據點都是分佈在-1,1.5之間的,所以我取-1,1.5的等差數列密度爲1000個,爲了可以佈滿整個圖像
    t2 = np.linspace(-1, 1.5, density)

    cordinates = [(x, y) for x in t1 for y in t2] #取得各個點的座標
    x_cord, y_cord = zip(*cordinates) #解壓
    mapped_cord = feature_mapping(x_cord, y_cord, power)  # 進行高次運算

    inner_product = np.array(mapped_cord) @ theta 

    decision = mapped_cord[np.abs(inner_product) < threshhold] #增加條件

    return decision.f10, decision.f01 #獲取x^1和y^1 用來畫邊界函數

def draw_boundury(power,l):
    density =1000
    threshhold= 2* 10**-3
    final_theta = feature_mapped_logistic_regression(power,l)
    x,y = find_decision_boundary(density, power, final_theta, threshhold)
    
    dt = pd.read_csv('E:/Data/Ng/Coursera-ML-AndrewNg-Notes-master/code/ex2-logistic regression/ex2data2.txt',names=['exam1','exam2','accepted'])
    sns.lmplot('exam1','exam2',hue = 'accepted',data=dt,height=6,fit_reg=False,scatter_kws={'s':50})
    
    plt.scatter(x,y,color='red',s=10)
    plt.title('Desicion Boundary')
    plt.show()

draw_boundury(power=6,l=1) 
draw_boundury(power=6,l=0) #過擬合
draw_boundury(power=6,l=50) #欠擬合

結果:
lambda=1比較合適
在這裏插入圖片描述

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

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