線性模型簡述與Python實現

線性模型

根據周志華《機器學習》和南京大學《人工智能導論》PPT進行學習和代碼練習的簡單整理。

線性擬合

使用線性模型擬合目標函數,用於模型預測
可以使用一般的線性函數,或者非線性的廣義線性模型
在這裏插入圖片描述

import numpy as np
import random
from copy import deepcopy
import matplotlib
from matplotlib import pyplot as plt
x = np.linspace(-1,1,50)
y = np.exp(0.1*x**2-1.6*x+7)
plt.figure(figsize=(8, 6.5))
plt.scatter(x,y,c='w',edgecolors='b')

在這裏插入圖片描述

#線性擬合
X = np.concatenate((x.reshape(-1,1),np.ones(len(x)).reshape(-1,1)),axis=1)
Y = y.reshape(-1,1)
W = np.linalg.inv(np.transpose(X).dot(X)).dot(np.transpose(X)).dot(Y)
plt.figure(figsize=(8, 6.5))
plt.scatter(x,y,c='w',edgecolors='b')
plt.plot(x,X.dot(W),c='r')

在這裏插入圖片描述

#使用廣義線性模型
X = np.concatenate((x.reshape(-1,1)**2,x.reshape(-1,1),
                    np.ones(len(x)).reshape(-1,1)),axis=1)
Y = np.log(y.reshape(-1,1))
W = np.linalg.inv(np.transpose(X).dot(X)).dot(np.transpose(X)).dot(Y)
plt.figure(figsize=(8, 6.5))
plt.scatter(x,y,c='w',edgecolors='b')
plt.plot(x,np.exp(X.dot(W)),c='r')

在這裏插入圖片描述

W
array([[ 0.1],
       [-1.6],
       [ 7. ]])

線性判別器

討論用線性函數二分類數據的問題,輸出的標記是0或1,所以
需要一個映射把線性函數映射到0和1之間,一般使用sigmoid
在這裏插入圖片描述

def sigmoid(x):
    return 1/(1+np.exp(-x))
from sklearn.datasets import load_iris
iris = load_iris()
descr = iris['DESCR']
data = iris['data']
feature_names = iris['feature_names']
target = iris['target']
target_names = iris['target_names']
#前100個樣例是0-1分類,我們就用這100個樣例來建立一個線性判別器
trainX = data[:100,:2]
trainY = target[:100].reshape(-1,1)
plt.figure(figsize=(8, 6.5))
colors = ['blue','red']
fig = plt.figure(figsize=(8,6.5))
plt.scatter(trainX[:,0].reshape(1,-1), trainX[:,1].reshape(1,-1),edgecolors='black',
            c=trainY.reshape(1,-1), cmap=matplotlib.colors.ListedColormap(colors))

在這裏插入圖片描述

class Logisic:
    def __init__(self, d):
        self.W = np.random.rand(d,1)
        self.b = np.random.rand(1)
        
        
    def fit(self,trainX,trainY):
        N = len(trainX)
        lr = 2
        for epoch in range(1000):
            f = sigmoid(trainX.dot(self.W)+self.b)
            if epoch%100==0:
                err = np.sum((f-trainY)**2)/N
                print("Error:",err)
            db = (f-trainY)*f*(1-f)
            dw = np.transpose(trainX).dot(db)/N
            db = np.sum(db)/N
            self.b -= lr*db
            self.W -= lr*dw
        print("--------")
    
    def predict(self, x):
        return round(sigmoid(x.dot(self.W)+self.b).reshape(-1)[0])
model = Logisic(2)
model.fit(trainX,trainY)
W,b = model.W,model.b
Error: 0.48974094514087235
Error: 0.02845106002345418
Error: 0.02349778257335842
Error: 0.020884907015279123
Error: 0.019227130294864208
Error: 0.018062500178454313
Error: 0.017189464964337958
Error: 0.01650486978561428
Error: 0.01594996225816542
Error: 0.015488601131152918
--------
x = np.linspace(4,8,50)
y = (-W[0]*x-b)/W[1]
fig = plt.figure(figsize=(8,6.5))
plt.scatter(trainX[:,0].reshape(1,-1), trainX[:,1].reshape(1,-1),edgecolors='black',
            c=trainY.reshape(1,-1), cmap=matplotlib.colors.ListedColormap(colors))
plt.plot(x,y,c='black')

在這裏插入圖片描述

線性判別分析

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

#線性判別分析,一種基於投影的判別模型
class LDA:
    def __init__(self):
        '''
        LDA參數包括訓練得到的方向向量
        和訓練中留下的投影均值向量值,這裏
        只設置兩個mu用於二分類
        '''
        self.w = None
        self.mu1 = None
        self.mu2 = None
        
    def fit(self, X1, X2):
        '''
        給出兩個種類的數據
        '''
        N1,N2 = len(X1),len(X2)
        #計算均值向量|
        u1,u2 = np.sum(X1,axis=0)/N1,np.sum(X2,axis=0)/N2
        #計算類內散度矩陣
        Sw = np.transpose((X1-u1)).dot(X1-u1)+\
        np.transpose(X2-u2).dot(X2-u2)
        self.w = np.linalg.inv(Sw).dot(u1-u2)
        self.mu1 = np.transpose(self.w).dot(u1)
        self.mu2 = np.transpose(self.w).dot(u2)
        return
    
    def predict(self, x):
        x = x.reshape(-1,1)
        if np.linalg.norm(self.mu1-self.w.dot(x))<\
        np.linalg.norm(self.mu2-self.w.dot(x)):
            return 0
        else:
            return 1
lda = LDA()
dataset = np.concatenate([data[:100,:2],
                         target[:100].reshape(-1,1)],axis=1)
np.random.shuffle(dataset)
trainset = dataset[:70]
testset = dataset[70:]
posi = [];nega = []
for i in range(70):
    if dataset[i][2]==0:
        nega.append(dataset[i][:2])
    else:
        posi.append(dataset[i][:2])
        
nega = np.array(nega)
posi = np.array(posi)

lda.fit(nega,posi)
labels = np.array([lda.predict(x[:2]) for x in testset]).reshape(-1)
plt.figure(figsize=(8, 6.5))
colors = ['blue','red']
fig = plt.figure(figsize=(8,6.5))
plt.scatter(testset[:,0].reshape(-1), testset[:,1].reshape(-1),edgecolors='black',
            c=labels, cmap=matplotlib.colors.ListedColormap(colors))

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-qvtDPdqV-1583050887225)(output_17_2.png)]

y = testset[:,2].reshape(-1)
accurate = labels==y
accuracy = np.sum(accurate)/len(accurate)
print("accuracy:",accuracy)
accuracy: 1.0

多分類

介紹了上面兩種二分類模型後,我們來討論如何用二分類模型進行多分類處理。
常用的有OVO OVR MOM的方式,一對一判別每次使用兩種樣本進行訓練,生成(N(N-1))/2個判別器。一對其餘判別每次使用所有樣本進行訓練,生成N個判別器。這兩者比較容易理解,就是在各個類別之間進行劃分。預測時OVO使用投票判別,OVR則使用置信程度最大的正判別結果。一般來說兩者訓練時間基本相同,一對一使用的內存和預測時間稍長,兩者的實際預測多數情況下相同。
MOM是多對多模型,每次選擇若干類爲正樣本,其餘爲反樣本進行訓練。這個過程比起確認的分類更復雜一些,這裏介紹ECOC技術。
對數據集進行M次劃分,生成M個判別器。每個判別器會把類別處理爲一個編碼,在用這M個模型共同預測時,會生成M個結果組成一個新的碼,最終通過計算海明/歐式距離選擇距離最小的類別作爲最終分類結果。

在這裏插入圖片描述

#使用全部iris數據集訓練三分類模型
#使用線性判別器和一對一技術
class Multiclassifier:
    def __init__(self, d, num):
        '''
        給定數據維度d和類別數num
        初始化一系列二分類模型
        labels用於標記當前使用的是分類哪兩個類別的模型
        '''
        self.num = num
        self.models = [Logisic(d) for _ in range(num*(num-1)//2)]
        self.labels = []
        for i in range(num):
            for j in range(i+1,num):
                self.labels.append((i,j))
        
        
    def fit(self, X, Y):
        '''
        首先把輸入分爲num類,然後對每個模型,
        從所有類別中選出兩類, 進行訓練
        '''
        Xs = [[] for _ in range(self.num)]
        for i in range(len(X)):
            Xs[int(Y[i])].append(X[i])
        for i in range(len(self.labels)):
            c1,c2 = self.labels[i]
            Y = np.concatenate((np.zeros(len(Xs[c1])),np.ones(len(Xs[c2]))))
            X = np.concatenate((np.array(Xs[c1]),np.array(Xs[c2])),axis=0)
            Y = Y.reshape(-1,1)
            self.models[i].fit(X,Y)
            
    def predict(self, x):
        votes = [0 for _ in range(self.num)]
        for i in range(len(self.models)):
            y = self.models[i].predict(x)
            y = int(y)
            votes[self.labels[i][y]]+=1
        argmax = 0
        for i in range(self.num):
            if votes[i]>votes[argmax]:
                argmax = i
        return argmax
mmodel = Multiclassifier(4,3)
dataset = np.concatenate((data,target.reshape(-1,1)),axis=1)
np.random.shuffle(dataset)
X = deepcopy(dataset[:,:-1])
Y = deepcopy(dataset[:,-1])
testX = deepcopy(X[105:])
testY = deepcopy(Y[105:])
X = X[:105]
Y = Y[:105:]
mmodel.fit(X,Y)
Error: 0.5068554045459038
Error: 0.5064866527545475
Error: 0.0033879018995723663
Error: 0.0014907218719421866
Error: 0.0009738340406175263
Error: 0.0007292282981414701
Error: 0.0005855832270019185
Error: 0.0004906739447541475
Error: 0.0004230996393875514
Error: 0.0003724331013397537
--------
Error: 0.5086999510528764
Error: 0.00047225598403563996
Error: 0.00033672925392112503
Error: 0.0002619009230266862
Error: 0.00021442440383014395
Error: 0.00018160518471669733
Error: 0.00015755486692888742
Error: 0.00013916817885224723
Error: 0.0001246520762975104
Error: 0.0001128986318560486
--------
Error: 0.5070586270183817
Error: 0.4539108823445084
Error: 0.5055794613745865
Error: 0.4344125451726819
Error: 0.3910297473905754
Error: 0.11004200305405856
Error: 0.055868433009766655
Error: 0.043752381106278444
Error: 0.03844468729988745
Error: 0.03686396198139862
--------
y = np.zeros(len(testX))
for i in range(len(testX)):
    c = mmodel.predict(testX[i])
    y[i] = c
accurate = y==testY
accuracy = np.sum(accurate)/len(accurate)
print("Accuracy:",accuracy)
Accuracy: 1.0

代碼與筆記均爲原創,轉載請註明

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