機器學習快速入門(迴歸與分類,線性與非線性,特徵空間)

這篇文章爲作者自學PRML時整理的筆記,適合想快速入門機器學習並瞭解一些基礎的相關算法的初學者閱讀。

多項式曲線擬合

我們從最基礎的機器學習方法說起,最基本的算法莫過於函數擬合了。多項式迴歸涉及到的知識是數據預處理(升維)、均方誤差MSE的使用、代數方程求解和數值優化方法的使用。如果要尋找合適的多項式階數可能還要用到正則化技巧和驗證集來輔助訓練。
首先我們把原數據進行升維到M階,並且設置偏置項(實際上這種方法並不僅限於多項式,我們可以隨意對X和y進行我們希望的變換,建立一個任意的線性組合的函數形式,再進行迴歸)然後按照線性迴歸的做法就能計算多項式的迴歸。線性迴歸的過程等價於最小化均方誤差,寫出等式可以解正規方程。f(x)=XW f(x)=XW
W=argminL(W) W = argmin \quad L(W) L(W)=(yXW)T(yXW) L(W)= (y-XW)^T(y-XW)
因爲優化目標函數是凸優化,直接計算偏導爲0就能得到閉式解。LW=2XT(XWy)=0 \frac{\partial L}{\partial W}= 2X^T(XW-y)=0
W=(XTX)1XTy W = (X^{T}X)^{-1}X^Ty
當然也可以直接用上面的梯度進行數值優化,進行多次梯度下降也可以得到一個穩定的解。這個方法在某些數據中某些維度出現缺失時也適用,而不用擔心矩陣不完整的問題。如果要在上面的基礎上再使用正則化,以L2正則爲例,我們在損失函數MSE的基礎上增加了一項λWTW\lambda W^TW懲罰項,這個方法能有效減小過擬合。再次計算梯度如下,我們就得到了新的,帶正則化項的閉式解
LW=2XT(XWy)+2λW=0 \frac{\partial L}{\partial W}= 2X^T(XW-y)+2\lambda W=0
W=(XTX+λI)1(XTy) W = (X^{T}X+\lambda I)^{-1}(X^Ty)
公式已經給出,下面我們藉助這個閉式解,直接寫一個多項式迴歸的算法。

import numpy as np
import matplotlib.pyplot as plt
import matplotlib
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import MinMaxScaler
def combination(deg,n):
    '''
    生成多個m長度的list,每個list都是和爲m的任意組合
    '''
    if n==1:
        return [[deg]]
    ret = []
    for i in range(deg+1):
        for postfix in combination(deg-i,n-1):
            ret.append([i]+postfix)
    return ret
combination(2,4)
[[0, 0, 0, 2],
 [0, 0, 1, 1],
 [0, 0, 2, 0],
 [0, 1, 0, 1],
 [0, 1, 1, 0],
 [0, 2, 0, 0],
 [1, 0, 0, 1],
 [1, 0, 1, 0],
 [1, 1, 0, 0],
 [2, 0, 0, 0]]
def dim_improve(X_raw, deg):
    '''
    多項式維度提升的算法,對X_raw裏的維度都計算0~deg次方
    '''
    n,m = X_raw.shape
    X = []
    for j in range(deg+1):
        # 遍歷0到deg階的所有組合
        combs = combination(j,m)
        for comb in combs:
            prod = 1
            for i in range(m):
                prod *= X_raw[:,i]**comb[i]
            X.append(prod)

    X = np.array(X).T
    return X
X_raw = np.array([[1],[2],[3]])
dim_improve(X_raw, 3)
array([[ 1,  1,  1,  1],
       [ 1,  2,  4,  8],
       [ 1,  3,  9, 27]], dtype=int32)
X_raw = np.array([[1,2],[4,3]])
dim_improve(X_raw, 2)
array([[ 1,  2,  1,  4,  2,  1],
       [ 1,  3,  4,  9, 12, 16]], dtype=int32)
def poly_fitting(X_raw, y, poly_degree, lamda = 0, plot = False):
    '''
    X raw,y;給定的數據集,需要提升階數,默認X,y爲2維numpy array
    poly degree;擬合的多項式最高階數
    lambda:L2正則的係數,係數越大懲罰越強
    返回多項式權重向量,維度爲poly degree+1
    '''
    deg = poly_degree
    # 首先提升維度,並增加偏置項
    X = dim_improve(X_raw,deg)
    
    n,m = X.shape
    W = np.linalg.inv(X.T.dot(X)+lamda*np.eye(m)).dot(X.T.dot(y))
    
    if plot:
        if X_raw.shape[1]>1:
            print("Can not plot data more than 1 dimension.")
        else:
            plt.figure()
            x_space_raw = np.linspace(np.min(X_raw),np.max(X_raw),100).reshape(-1,1)
            x_space = dim_improve(x_space_raw,deg)
            y_space = x_space.dot(W)
            plt.plot(x_space_raw, y_space)
            plt.scatter(X_raw, y, c = 'r', marker = 'x')
        
    return X,W
X = np.linspace(0,0.9,10).reshape(-1,1)
y = np.sin(X*2*np.pi)
y += np.array([0.2, 0.1, 0, 0.05, -0.1, 0.4, 0, 0.35, 0.05, 0.2]).reshape(-1,1)

poly_fitting(X, y, 0, 0, True)
poly_fitting(X, y, 1, 0, True)
poly_fitting(X, y, 3, 0, True)
poly_fitting(X, y, 9, 0, True)

print()

在這裏插入圖片描述

在這裏插入圖片描述

在這裏插入圖片描述

方差-偏差陷阱

在上面看到,階數degree = 9時,曲線很好的逼進了每個點,但是很顯然,得到的曲線並不是我們真正想要的曲線,在訓練集上表現得很好但泛化性較差的模型我們稱之爲過擬合,它具有"較大方差"。類似的,像階數爲0和1時,曲線並沒有擬合到所有數據上,這時我們稱之爲欠擬合,它具有"較大偏差"。
儘管選擇合適的多項式階數能在上面的問題裏湊效,但實際問題卻往往不是稱心如意。爲此,上面已經實現了的正則化技巧將會派上用場,爲了驗證泛化能力,我們還要特地準備和訓練集分佈類似的驗證集,以模型在驗證集上的誤差爲準,測試找到最合適的正則化方法和係數。

poly_fitting(X, y, 9, 0.001, True)

print()

在這裏插入圖片描述

迴歸問題的概率解釋與貝葉斯迴歸

概率機器學習流派一直嘗試使用概率方法解釋機器學習問題和算法,事實上概率模型也的確在機器學習的發展上有着巨大的推動作用。很多機器學習算法就是完全基於統計概率建模的,比如NB樸素貝葉斯,貝葉斯網絡,以及高斯混合模型、Fisher判別以及語音處理裏常用的馬爾科夫模型等。
概率模型也可以解釋很多經典的算法,比如一般的MSE損失函數優化,就可以通過引入額外的概率分佈把MSE誤差變換成概率,原優化問題就變成最大化對數概率似然。貝葉斯迴歸使用的技巧是,把真實數據點和函數模型之間的偏差視作噪聲,我們假設噪聲符合高斯分佈,因爲這個分佈的自變量只有y這一維,我們可以寫出一維情形的高斯分佈函數N(μ,σ2)=N(wx,σ2) N(\mu,\sigma^2) = N(wx,\sigma^2)
其中均值是函數模型的預測值,方差則視爲超參,需要自行調節。對模型W和數據集中所有數據點,計算對數似然如下
L(W)=log(ni=112πσexp((yiwx)22σ))=log(12πn2σn)+ni=1((yiwx)22σ) L(W) = log(\prod _{n}^{i=1}\frac{1}{\sqrt{2\pi}\sigma}exp(-\frac{(y_i-wx)^2}{2\sigma}))=log(\frac{1}{2\pi^{\frac{n}{2}}\sigma^n})+\sum _{n}^{i=1}(-\frac{(y_i-wx)^2}{2\sigma})
我們的目的是最大化對數似然,優化問題等價於W=argmaxni=1((yiwx)22σ) W=argmax\quad \sum _{n}^{i=1}(-\frac{(y_i-wx)^2}{2\sigma})
我們會發現優化問題又變成了一個最小化MSE的過程,而在此之上,我們又能推導來自貝葉斯學派的貝葉斯線性迴歸。這部分知識相對更繁瑣,我會在課後補充裏詳細講解並實現貝葉斯線性迴歸。

迴歸問題實例

下面我們看一個基於上面的迴歸算法實現的實例,波士頓房價擬合。

# 迴歸問題實例,線性迴歸波士頓房價問題
from sklearn.datasets import load_boston
boston = load_boston()
descr = boston['DESCR']
data = boston['data']
feature_names = boston['feature_names']
target = boston['target']

X = data.copy()
y = target.copy()


X_train, X_test, y_train, y_test = train_test_split( X, y, test_size = 0.2, random_state = 0)

#數據標準化處理
sc_X = StandardScaler()
X_train = sc_X.fit_transform(X_train)
X_test = sc_X.transform(X_test)

X_poly, W = poly_fitting(X_train,y_train,1)
#計算訓練集和測試集上的L1誤差
out = X_poly.dot(W)
err = np.mean(np.abs(out-y_train.squeeze()))
print("L1 loss on training set: %.2f"%(err))

X_poly = dim_improve(X_test,1)
out = X_poly.dot(W)
err = np.mean(np.abs(out-y_test.squeeze()))
print("L1 loss on testing set: %.2f"%(err))
L1 loss on training set: 3.10
L1 loss on testing set: 3.84

注:任何使用高階多項式的技術都要進行適當的預處理,把數據縮放到-1,1區間,否則原本很小的數值將變得非常巨大(指數爆炸)。如果數據在某些維度的分佈稀疏或不均勻,可以嘗試用對數座標,或者PCA降維,以及其他度量學習的技術進行預處理

# 爲了使用多項式迴歸,我們需要先把數據歸一到0,1區間

min_max_scaler = MinMaxScaler()
X_01 = min_max_scaler.fit_transform(X)
X_train, X_test, y_train, y_test = train_test_split( X_01, y, test_size = 0.2, random_state = 0)

# 使用二階多項式,因爲高階項的存在,我們需要嘗試不同的lambda正則化來加強模型泛化能力
train_loss = []
test_loss = []
lamda_list = [0.001*2**i for i in range(14)]

for lamda in lamda_list:

    X_poly, W = poly_fitting(X_train,y_train,2,lamda)
    #計算訓練集和測試集上的L1誤差
    out = X_poly.dot(W)
    err = np.mean(np.abs(out-y_train.squeeze()))
    train_loss.append(err)

    X_poly = dim_improve(X_test,2)
    out = X_poly.dot(W)
    err = np.mean(np.abs(out-y_test.squeeze()))
    test_loss.append(err)

plt.plot(train_loss,label='training loss')
plt.plot(test_loss,label='testing loss')
plt.title('Boston house prize regression-L1 loss')
plt.ylabel('loss')
plt.xlabel('power of lambda')
plt.legend()

在這裏插入圖片描述

分類決策

數據擬合有着很好的應用,我們可以在原數據上進行自己想要的函數形式擬合,從而得到一個很可能有意義的函數形式。但很多時候我們想要的不僅僅是擬合,我們或許會面臨:得到數據集,每個數據都有自己的特徵向量(或離散或連續),並且有一個對應的分類標籤,除此之外並沒有任何其他信息,我們能不能學習到一個決策器模型幫助我們分類數據呢?
我們當然可以把問題直接視爲擬合問題,假設我們面臨二分類問題,標籤分別是0和1,如果把標籤視爲要回歸的y,上面的算法一樣可以跑起來,但是這並不是一個明智的做法,因爲在0-1交界處的函數斜率可能會非常大,而除此之外的地方函數斜率非常小,這樣的曲面很難用迴歸學習(用有參數模型固然很難,但後面我們會介紹一些能把這個任務做的很好的算法)。比較理智的做法是引入sigmoid函數 σ(x)=11+exp(x) \sigma(x)=\frac{1}{1+exp(-x)}

xx = np.linspace(-5,5,100)
yy = 1/(1+np.exp(-xx))
plt.plot(xx,yy)
plt.title('Sigmoid')
Text(0.5,1,'Sigmoid')

在這裏插入圖片描述

我們把sigmoid中的x用上面函數擬合裏的y=f(x)換掉,則能讓f(x)>0時y輸出爲0.5以上,<0時輸出爲0.5以下;因爲sigmoid正具備着中間斜率大,兩邊斜率小的特徵,如果把這個輸出y視爲新的輸出函數值,則能把y的區間壓縮到0到1之間,這樣再對0-1標籤迴歸可能會容易很多。
除此之外,sigmoid還有容易求導的性質,計算一下就發現,dσdx=y(1y) \frac{d\sigma}{dx} = y(1-y)
我們寫出線性函數和sigmoid組合後的函數形式,計算它與目標標籤的均方誤差,就得到了分類問題的優化目標。
y=σ(o)=σ(wx) y = \sigma(o) = \sigma(wx)
argminL(w)=12Ni=1n(yiyi^)2 argmin\quad L(w) = \frac{1}{2N}\sum_{i=1}^{n}(y_i-\hat{y_i})^2
這個誤差函數MSE因爲非線性函數sigmoid存在,不再容易計算正規方程。但是我們一樣有方法求解,比如上面已經提到的梯度下降,我們寫出L關於w的梯度
Lw=1Ni=1n(yiyi^)yi(1yi)xi \frac{\partial{L}}{\partial{w}}=\frac{1}{N}\sum_{i=1}^{n}(y_i-\hat{y_i})y_i(1-y_i)x_i
寫成代數形式就是 Lw=1NXT((yiyi^)yi(1yi)) \frac{\partial{L}}{\partial{w}}=\frac{1}{N}X^T((y_i-\hat{y_i})*y_i*(1-y_i))
我們只需要設置一個學習率alpha,再用梯度下降不斷更新參數即可
wwαLw w \leftarrow w-\alpha\frac{\partial{L}}{\partial{w}}
不過基於MSE做迴歸雖然能跑起來,但是存在一個問題,假設有樣本標籤爲1,但是被錯分在了0;這時sigmoid對它的輸出值爲接近於0,處於sigmoid的兩端,但是sigmoid在兩端的導數是非常小的。這樣下去儘管參數在更新,但更新速度非常的慢,這自然不是我們需要的。我們希望,數據被誤判的程度越大,更新速率就越大。爲此我們可能需要更好的優化目標。如果我們把sigmoid輸出的數值,看做數據分類爲1的概率,則可以從最大化對數概率的角度考慮。
argmaxL(w)=i=1n(yilog(σ(o))+(1yi)log(1σ(o)))=i=1n(yilog(p)+(1yi)log(1p)) argmax\quad L(w)=\sum_{i=1}^{n}(y_i log(\sigma(o))+(1-y_i) log(1-\sigma(o)))=\sum_{i=1}^{n}(y_i log(p)+(1-y_i) log(1-p))
這個loss又被稱爲BCEloss,二分類交叉熵。log函數的引入會讓輸出越遠離目標,就有越大的斜率。對這個新的函數計算w的梯度
Lw=i=1n(yip(1p)p(1yi)p(1p)1p)xi=i=1n(yi(1p)(1yi)p)xi=i=1n(yip)xi \frac{\partial{L}}{\partial{w}}=\sum_{i=1}^{n}(\frac{y_i p(1-p)}{p}-\frac{(1-y_i) p(1-p)}{1-p})x_i= \sum_{i=1}^{n}(y_i (1-p)-(1-y_i) p)x_i=\sum_{i=1}^{n}(y_i-p)x_i
梯度更適合訓練,目標與實際的相差越大,對應的參數得到的變化量也就越大。上面的基於線性迴歸進行二分類的技術稱爲logistic迴歸,我們可以編程實現一下。

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

class Logisic:
    def fit(self,X,y,lr = 0.01,max_iter = 500, plot_every_iters = 100):
        '''
        接收數據特徵X和標籤y,需要X爲NxM的二維numpy array
        y爲數值爲0-1的一維numpy array,學習率和迭代次數自行調節
        '''
        n,m = X.shape
        y = y.reshape(-1,1)
        self.W = np.random.rand(m,1)
        self.b = np.random.rand(1)
        
        for iters in range(max_iter):
            p = sigmoid(X.dot(self.W)+self.b)  # 計算概率
            if (iters+1)%plot_every_iters==0:
                err = np.mean(-y*np.log(p)-(1-y)*np.log(1-p))  # BCE loss
                print("Iteration: %d, BCE loss: %.2f"%(iters+1,err))
            db = y-p # BCE loss的梯度計算
            dw = X.T.dot(db)/n
            db = np.sum(db)/n
            # 最大化對數似然,使用梯度上升法
            self.b += lr*db
            self.W += lr*dw
    
    def predict(self, X):
        '''
        輸入x爲任意n,固定m的二維numpy array
        '''
        return np.round(sigmoid(X.dot(self.W)+self.b))

我們用乳腺癌二分類數據集來測試算法性能,一般在處理真實數據前,爲了讓數據易於學習,需要先對數據標準化處理。

from sklearn.datasets import load_breast_cancer
cancer = load_breast_cancer()
descr = cancer['DESCR']
data = cancer['data']
feature_names = cancer['feature_names']
target = cancer['target']
target_names = cancer['target_names']
X = data.copy()
y = target.copy()

X_train, X_test, y_train, y_test = train_test_split( X, y, test_size = 0.25)

sc_X = StandardScaler()
X_train = sc_X.fit_transform(X_train)
X_test = sc_X.transform(X_test)
model = Logisic()
model.fit(X_train,y_train,0.01,1000)
Iteration: 100, BCE loss: 0.56
Iteration: 200, BCE loss: 0.25
Iteration: 300, BCE loss: 0.19
Iteration: 400, BCE loss: 0.17
Iteration: 500, BCE loss: 0.15
Iteration: 600, BCE loss: 0.13
Iteration: 700, BCE loss: 0.12
Iteration: 800, BCE loss: 0.12
Iteration: 900, BCE loss: 0.11
Iteration: 1000, BCE loss: 0.10
accuracy_score(model.predict(X_test).reshape(-1),y_test)
0.951048951048951

由於訓練集和測試集劃分的隨機性,測試集上的正確率可能有細微差別,不過無傷大雅;我們可以看見邏輯迴歸能夠很好的處理這個二分類問題,並取得90per以上的正確率。因爲breast cancer數據集有比較好的線性可分性質,邏輯迴歸可以得到比較理想的結果。但不免有時會出現不是線性可分的數據,這時我們也可以用上面函數擬合時使用的多項式迴歸技術,把原數據做升維處理,再嘗試進行線性劃分。當然,分類問題也可以用正則化來避免過擬合。

# 設計不是線性可分的數據集
X = np.random.rand(2,100)
y = (X[1]<np.sin(X[0]*np.pi)*0.7)
y = y.astype(np.int)
X = X.T
plt.scatter(X[:,0].squeeze(),X[:,1].squeeze(),c=y, marker='x')
<matplotlib.collections.PathCollection at 0x21976536dd8>

在這裏插入圖片描述

def decision_plain(model, low1, upp1, low2, upp2):
    x_axis = np.linspace(low1,upp1,100)
    y_axis = np.linspace(low2,upp2,100)
    xx, yy = np.meshgrid(x_axis, y_axis)
    Z = np.zeros((100,100))
    for i in range(100):
        for j in range(100):
            
            Z[i][j] = model.predict(np.array([xx[i][j],yy[i][j]]))
    plt.figure(figsize=(8,6), dpi=80)
    colors = ['aquamarine','palegoldenrod']
    plt.contourf(xx, yy, Z, cmap=matplotlib.colors.ListedColormap(colors))
model = Logisic()
model.fit(X,y,0.1,5000,1000)
print("accuracy:",accuracy_score(model.predict(X).reshape(-1),y))
decision_plain(model,-0.1,1.1,-0.1,1.1)
plt.scatter(X[:,0].squeeze(),X[:,1].squeeze(),c=y, marker='x')
Iteration: 1000, BCE loss: 0.45
Iteration: 2000, BCE loss: 0.43
Iteration: 3000, BCE loss: 0.42
Iteration: 4000, BCE loss: 0.42
Iteration: 5000, BCE loss: 0.42
accuracy: 0.76





<matplotlib.collections.PathCollection at 0x21972f6d9b0>

在這裏插入圖片描述

def decision_plain_poly(model, deg, low1, upp1, low2, upp2):
    x_axis = np.linspace(low1,upp1,100)
    y_axis = np.linspace(low2,upp2,100)
    xx, yy = np.meshgrid(x_axis, y_axis)
    Z = np.zeros((100,100))
    for i in range(100):
        for j in range(100):
            inpt = np.array([[xx[i][j],yy[i][j]]])
            inpt = dim_improve(inpt, deg)
            Z[i][j] = model.predict(inpt)
    plt.figure(figsize=(8,6), dpi=80)
    colors = ['aquamarine','palegoldenrod']
    plt.contourf(xx, yy, Z, cmap=matplotlib.colors.ListedColormap(colors))
# 進行多項式維度提升
deg = 6
X_poly = dim_improve(X, deg)
model = Logisic()
model.fit(X_poly,y,0.1,5000,1000)
print("accuracy:",accuracy_score(model.predict(X_poly).reshape(-1),y))
decision_plain_poly(model,deg,-0.1,1.1,-0.1,1.1)
plt.scatter(X[:,0].squeeze(),X[:,1].squeeze(),c=y, marker='x')
Iteration: 1000, BCE loss: 0.33
Iteration: 2000, BCE loss: 0.28
Iteration: 3000, BCE loss: 0.26
Iteration: 4000, BCE loss: 0.24
Iteration: 5000, BCE loss: 0.22
accuracy: 0.89





<matplotlib.collections.PathCollection at 0x219765de2e8>

在這裏插入圖片描述

一個基本的思想是,數據在通過某種映射被映射到高維空間後,一般會變得更線性可分。這個映射也不必一定是多項式,也可以是高斯函數,sigmoid函數等,這個技巧又被稱爲核方法,我們將在後面的學習中更詳細的介紹它們。但是以多項式爲代表的這些核方法都變臨一個問題,即維度災難。上面的例子我們在原本的二維空間裏使用6階多項式,這就把數據空間擴大到了28維。如果我們的數據維度像上面的乳腺癌數據集一樣,原本就擁有30個維度,那麼在此之上使用多項式產生的新維度將非常多,這顯然是無法接受的。爲此,我們或許需要更好的非線性方法,這些方法我們在後面的學習中將會進一步介紹。

Fisher判別

Fisher判別器沒有使用非線性的技巧,而是純粹基於線性變換進行的分類算法。首先還是做一個線性變換y=wx,然後我們希望同類樣本的y相似,而不同樣本的y差別較大。如果這個假設在問題上合理,則我們就能用一類樣本的y的均值作爲類別中心,以樣本離各聚類中心的距離來進行數據分類。
首先定義類間距離和類內距離,類間距就是兩個類中心的距離,類內距就是所有數據點到類中心的距離均值
J0=((μ1μ0)W)T((μ1μ0)W)=WT(μ1μ0)T(μ1μ0)WJ_0=((\mu_1-\mu_0)W)^T((\mu_1-\mu_0)W)=W^T(\mu_1-\mu_0)^T(\mu_1-\mu_0)W
J1=((Xμ)W)T((Xμ)W)=WT(Xμ)T(Xμ)WJ_1=((X-\mu)W)^T((X-\mu)W)=W^T(X-\mu)^T(X-\mu)W
我們設S1=(Xμ)T(Xμ),S0=(μ1μ0)T(μ1μ0)S_1=(X-\mu)^T(X-\mu),S_0 = (\mu_1-\mu_0)^T(\mu_1-\mu_0)
有了這兩個量就可以自己定義損失函數了,一種能保證數據規模不會影響loss的方法是設J1=1,最大化J0。即J=WTS0Ws.t.WTS1W=1J=W^TS_0W \quad s.t.\quad W^TS_1W=1
這個問題直接用拉格朗日乘子法就能求解,寫出拉格朗日函數
L(W,λ)=WTS0Wλ(WTS1W1) L(W,\lambda)=W^TS_0W-\lambda (W^TS_1W-1)
計算偏導並讓它等於0,就得到
LW=2WTS0W2λWTS1=0 \frac{\partial{L}} {\partial{W}}=2W^TS_0W-2\lambda W^TS_1=0
S0W=λS1W S_0W=\lambda S_1W
S11S0W=λW S_1^{-1}S_0W=\lambda W
和PCA的推導很類似,即特徵值分解。因爲我們要最大化目標函數,我們取S_1^{-1}S_0最大的特徵向量,就得到了最優解W。計算均值就能進行判別。如果我們取前d個最大的特徵向量,就能實現從原數據域降維到d維的線性變換矩陣。

class Fisher:
    def fit(self,X,y):
        '''
        接收數據特徵X和標籤y,需要X爲NxM的二維numpy array
        y爲數值爲0-1的一維numpy array
        '''
        # 分爲正負樣本
        X_1 = X[np.where(y==1)]
        X_0 = X[np.where(y==0)]
        # 計算均值
        mu1 = np.mean(X_1,axis = 0)
        mu0 = np.mean(X_0,axis = 0)
        self.mu1 = mu1
        self.mu0 = mu0
        # 類內散度
        S1 = (X_1-mu1).T.dot((X_1-mu1))
        # 類間散度
        S0 = (mu1-mu0).reshape(-1,1).dot((mu1-mu0).reshape(1,-1))
        # 特徵值分解
        S = np.linalg.inv(S1).dot(S0)
        lamda,V=np.linalg.eigh(S)
        #取前dim個最大的特徵值對應的特徵向量
        index=np.argsort(-lamda)[0]
        V_selected=V[:,index]
        self.W = V_selected
        return self.W
        
    
    def predict(self, X):
        '''
        輸入x爲任意n,固定m的numpy array
        '''
        n,m = X.shape
        dy = np.concatenate([(X-self.mu0).dot(self.W),
                             (X-self.mu1).dot(self.W)])
        dy = np.abs(dy.reshape(2,n))
        return np.argmin(dy.T,axis = 1)
model = Fisher()
model.fit(X_train,y_train)
array([-2.07796049e-01, -1.09919448e-01, -1.78434628e-01, -1.33270647e-01,
       -1.07895737e-01, -1.71313325e-01, -2.23547313e-01, -2.28560020e-01,
       -9.41916043e-02,  5.02942834e-04, -1.45142141e-01,  1.23362826e-03,
       -1.65254987e-01, -2.09242413e-01,  1.00610442e-02, -8.75431823e-02,
       -1.01180651e-01, -1.30609007e-01, -2.53573528e-03, -3.74411104e-02,
        4.33011915e-02, -1.25613150e-01, -1.58208041e-01, -7.54773156e-01,
        1.92460702e-03, -3.73331062e-02,  2.28623448e-02,  1.13842185e-02,
       -3.26370555e-03,  2.85204429e-03])
accuracy_score(model.predict(X_test).squeeze(),y_test)
0.9020979020979021

如果要評價Fisher線性判別分析和邏輯迴歸孰優孰劣,一般邏輯迴歸在分類問題上的表現都會好過線性判別分析。因爲線性判別分析就是把數據線性投影到1維,投影能解決的問題,邏輯迴歸都能解決。但是線性判別分析可以實現有標籤的數據降維,我們認爲在有標籤時,LDA的表現一定好過PCA在無標籤下的表現。降維不僅可以實現非常好看的數據可視化,很多時候還可以幫助模型訓練。而邏輯迴歸,最大的作用是搭建神經網絡。

多分類

在樣本類別較少時,我們可以採取1對多的構造方式,對N個類別,要搭建N個二分類器,預測時進行N次計算,選擇置信度最大的分類。在樣本類別很多時,1對多的方式不但要構造多個分類器,還會面臨樣本不均衡的問題,這時我們可以隨機構建多個多對多分類器。對數據集進行M次劃分,生成M個判別器。每個判別器會把類別處理爲一個編碼,比如對某個類,5個判別器分別預測爲-±++,則編碼爲01011。在用這M個模型共同預測時,會生成M個結果組成一個新的碼,最終通過計算海明/歐式距離選擇距離最小的類別作爲最終分類結果。比如5個判別器對樣本預測爲00101,而每個類別對應的編碼爲01011,10010,01101,00110。我們選擇海明距離最小的01101,第三類作爲分類結果。
在這裏插入圖片描述
在這裏插入圖片描述

小結

上面我們已經簡單介紹了什麼是數據的特徵,用基於多項式的升維方法實現非線性,常用的預處理手段,包括標準化、歸一化,怎樣實現線性迴歸和邏輯迴歸,並用正則化控制過擬合。如果你希望進一步學習機器學習,那麼我建議你學習一些常見的高級非線性機器學習模型,比如SVM和神經網絡,並且瞭解貝葉斯理論和structured learning。

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