感知機(perceptron)是二類分類的線性分類模型,其輸入爲實例的特徵向量,輸出爲實例的類別,取+1和-1二值.感知機對應於輸入空間(特徵空間)中將實例劃分爲正負兩類的分離超平面,屬於判別模型.感知機學習旨在求出將訓練數據進行線性劃分的分離超平面,爲此,導入基於誤分類的損失函數,利用梯度降低法對損失函數進行極小化,求得感知機模型.感知機學習算法具備簡單而易於實現的優勢,分爲原始形式和對偶形式.感知機預測是用學習獲得的感知機模型對新的輸入實例進行分類html
假設輸入空間(特徵空間)是,輸出空間是
,輸入
表示實例的特徵變量,對應於輸入空間(特徵空間)的點;輸出
表示實例的類別.由輸入空間到輸出空間的以下函數:
python
稱爲感知機.其中,w和b爲感知機模型函數,叫做權值(weight)或權值向量(weight vector),
叫做偏置(bias)
表示w和x的內積,sign是符號函數,即:
web
感知機是一種線性分類模型,屬於判別模型.感知機模型的假設空間時定義在特徵空間(linear classification model)或線性分類器(linear classifier),即函數集合算法
感知機有以下幾何解釋,線性方程:
對應於特徵空間中的一個超平面S,其中w是超平面的法向量,b是超平面的截距.這個超平面將特徵空間劃分爲兩個部分.位於兩部分的點(特徵向量)分爲正,負兩類.所以.超平面S稱爲分離超平面(separating hyperplane):app
from IPython.display import Image Image(filename="./data/2_1.png",width=500)
感知機學習,由訓練數據集(實例的特徵向量機類別):
dom
其中,,求得感知機模型.即求得模型參數w,b.感知機預測,經過學習獲得的感知機模型.對於新的輸入實例給出其對應的輸出示例svg
給定一個數據集:
函數
其中,若是存在某個超平面S:
學習
可以將數據集的正實例點和負實例點徹底正確地劃分到超平面的兩側,即對全部 的實例i,有 ,多全部 的實例i,有 ,則稱數據集T爲線性可分數據集(linearly separable data set);不然,稱數據集T線性不可分優化
假設訓練數據集是線性可分的,感知機學習的目標是求得一個可以將訓練集正實例點和負實例點徹底正確分開的分離超平面.爲了找出這樣的超平面.即肯定感知機模型參數w,b,須要肯定一個學習策略.即定義損失函數並將損失函數最小化
損失函數的一個目標選擇是誤分類點的總數.可是這樣的損失函數不是參數w,b的連續可導函數.損失函數的另外一個選擇是誤分類點到超平面S的總距離,這是感知機所採用的.爲此首先輸入空間中任一點
到超平面S的距離
對於誤分類的數據來講:
當時,
.而當
時,
.所以誤分類點
到超平面S的距離是:
假設超平面S的誤分類點集合爲M,那麼全部誤分類點到超平面S的總距離爲:
不考慮,就獲得感知機學習的損失函數
給定訓練數據集:
其中,感知機
學習的損失函數定義爲:
其中M爲誤分類點的集合,這個損失函數就是感知機學習的經驗風險函數
顯然,損失函數L(w, b)是非負的,若是沒有誤分類點,損失函數值是0.並且誤分類點越少,誤分類點離超平面越近,損失函數值就越小.一個特定的樣本點的損失函數,在誤分類時是參數w,b的線性函數,在正確分類時是0.所以給定訓練數據集T,損失函數L(w, b)是w,b的連續可導函數
感知機學習問題轉化爲求解損失函數的最優化問題,最優化的方法是隨機梯度降低法.具體方法包括原始形式和對偶形式,並證實在訓練數據線性可分條件下感知機學習算法的收斂性
感知機學習算法是對如下最優化問題的算法,給定一個訓練數據集:
其中,,求參數w,b使其爲如下損失函數極小化問題的解:
其中M爲誤分類點的集合
感知機學習算法是誤分類驅動的,具體採用隨機梯度降低法(stochastic gradient descent).首先任意選取一個超平面,而後用梯度降低法不斷地極小化目標函數.極小化過程不是一次使M中全部誤分類點的梯度降低,而是一次隨機選取一個2誤分類點使其梯度降低
假設誤分類集合M是固定的,那麼損失函數的梯度由:
隨機選取一個誤分類點,對w,b進行更新:
式中是步長,在統計學習中又稱爲學習率(learning rate).經過迭代能夠期待損失函數
不斷減少,直到爲0.綜上所述,獲得以下算法:
感知機學習算法的原始形式
輸入:訓練數據集,其中
, 學習率
輸出:w,b;感知機模型
這種學習算法直觀上有以下解釋:當一個實例點被誤分類,即位於分離超平面的錯誤一側時,則調整w,b的值,使分離超平面向該誤分類點的一側移動,以減小該誤分類點與超平面間的距離.直至超平面越過該誤分類點使其被正確分類
實例1:以下數據集,其正實例點是.試用感知機學習算法的原始形式求感知機模型
.這裏
from IPython.display import Image Image(filename="./data/3_1.png",width=500)
解:構建最優化問題
求解w,b,
如此繼續下去,直到:
對全部數據點,沒有誤分類點,損失函數達到極小
分離超平面爲:
感知機模型爲:
Image(filename="./data/2_3.png")
Image(filename="./data/2_4.png")
迭代次數 | 誤分類點 | w | b | w.x+b |
---|---|---|---|---|
0 | 0 | 0 | 0 | 0 |
1 | x1 | (3,3) | 1 | 3x1+3x2+1 |
2 | x3 | (2,2) | 0 | 2x1+2x2 |
3 | x3 | (1,1) | -1 | x1+x2-1 |
4 | x3 | (0,0) | -2 | -2 |
5 | x1 | (3,3) | -1 | 3x1+3x2-1 |
6 | x3 | (2,2) | -2 | 3x1+3x2-2 |
7 | x3 | (1,1) | -3 | x1+x2-2 |
8 | x1 | (1,1) | -3 | x1+x2-3 |
這是在計算中誤分類點前後取獲得的分離超平面和感知機模型.若是在計算中誤分類點依次取
,那麼獲得的分離超平面是$2
可見,感知機學習算法因爲採用不一樣的初值或選取不一樣的誤分類點,解能夠不一樣
對於線性可分數據集感知學習算法原始形式收斂,即通過有限次迭代能夠獲得一個將訓練數據集徹底正確劃分的分離超平面及感知機模型
誤分類的次數k是有上界的,通過有限次搜索能夠找到將訓練集數據徹底正確分開的分離超平面
對偶形式的基本想法是,將w和b表示爲實例x_和標記y_的線性組合的形式.經過求解其係數而求得w和b,不失通常性.在原始形式的算法中可假設初始值均爲0,對誤分類點
經過:
逐步修改w,b,設修改n次,則w,b關於的增量分別是
和
,這裏
.這樣學習過程不難看出最後學習到的w,b能夠分別表示爲:
這裏,,當
時,表示第i個實例點因爲誤分而進行更新的次數,實例點更新次數越多,意味着它距離分離超平面越近,也就越難正確分類,換句話說,這樣的實例對學習結果影響最大
感知機學習算法的對偶形式
輸入:線性可分的數據集,其中
學習率
輸出:a,b;感知機模型
其中
在訓練集中選取數據
若是
對偶形式中訓練實例僅之內積的形式出現,爲了方便,能夠預先將訓練集中實例間的內積計算出來並以矩陣的形式存儲,這個存儲就是所謂的Gram矩陣(Gram matrix)
實例2:正樣本點是負樣本點是
,試用感知機學習算法對偶形式求感知機模型
解:
與原始形式同樣,感知機學習算法的對偶形式迭代是收斂的,存在多個解
當實例點被誤分類,即位於分離超平面的錯誤側,則調整w,b的值,使分離超平面向該無分類點的一側移動,直至誤分類點被正確分類
拿出iris數據集中兩個分類的數據和[speal length,speal width]做爲特徵
%matplotlib inline import pandas as pd import numpy as np from sklearn.datasets import load_iris import matplotlib.pyplot as plt
# load iris iris=load_iris() df=pd.DataFrame(iris.data,columns=iris.feature_names) df["label"]=iris.target
df.columns=["sepal length","sepal width","petal length","petal width","label"] df.label.value_counts()
2 50 1 50 0 50 Name: label, dtype: int64
plt.scatter(df[:50]["sepal length"],df[:50]["sepal width"],label="0") plt.scatter(df[50:100]["sepal length"],df[50:100]["sepal width"],label="1") plt.xlabel("sepal length") plt.ylabel("sepal width") plt.legend()
<matplotlib.legend.Legend at 0x25ffdd3b6a0>
data=np.array(df.iloc[:100,[0,1,-1]])
X,y=data[:,:-1],data[:,-1]
y=np.array([1 if i==1 else -1 for i in y])
# 數據線性可分,二分類數據 # 此處爲一元一次線性方程 class Model(object): def __init__(self): self.w=np.ones(len(data[0])-1,dtype=np.float32) self.b=0 self.l_rate=0.1 def sign(self,x,w,b): y=np.dot(x,w)+b return y # 隨機梯度降低法 def fit(self,X_train,y_train): is_wrong=False while not is_wrong: wrong_count=0 for d in range(len(X_train)): X=X_train[d] y=y_train[d] if y*self.sign(X,self.w,self.b)<=0: self.w=self.w+self.l_rate*np.dot(y,X) self.b=self.b+self.l_rate*y wrong_count+=1 if wrong_count==0: is_wrong=True return "Perceptron Model!" def score(self): pass
perceptron=Model() perceptron.fit(X,y)
'Perceptron Model!'
x_points=np.linspace(4,7,10) y_=-(perceptron.w[0]*x_points+perceptron.b)/perceptron.w[1] plt.plot(x_points,y_) plt.plot(data[:50,0],data[:50,1],"bo",color="blue",label="o") plt.plot(data[50:100,0],data[50:100,1],"bo",color="orange",label="l") plt.xlabel("sepal length") plt.ylabel("sepal width") plt.legend()
<matplotlib.legend.Legend at 0x25fff517fd0>
from sklearn.linear_model import Perceptron clf=Perceptron(fit_intercept=False,max_iter=1000,shuffle=False) clf.fit(X,y)
E:\Anaconda\envs\mytensorflow\lib\site-packages\sklearn\linear_model\stochastic_gradient.py:183: FutureWarning: max_iter and tol parameters have been added in Perceptron in 0.19. If max_iter is set but tol is left unset, the default value for tol in 0.19 and 0.20 will be None (which is equivalent to -infinity, so it has no effect) but will change in 0.21 to 1e-3. Specify tol to silence this warning. FutureWarning) Perceptron(alpha=0.0001, class_weight=None, early_stopping=False, eta0=1.0, fit_intercept=False, max_iter=1000, n_iter=None, n_iter_no_change=5, n_jobs=None, penalty=None, random_state=0, shuffle=False, tol=None, validation_fraction=0.1, verbose=0, warm_start=False)
# weight assigned to the features print(clf.coef_)
[[ 74.6 -127.2]]
print(clf.intercept_)
[0.]
x_ponits = np.arange(4, 8) y_ = -(clf.coef_[0][0]*x_ponits + clf.intercept_)/clf.coef_[0][1] plt.plot(x_ponits, y_) plt.plot(data[:50, 0], data[:50, 1], 'bo', color='blue', label='0') plt.plot(data[50:100, 0], data[50:100, 1], 'bo', color='orange', label='1') plt.xlabel('sepal length') plt.ylabel('sepal width') plt.legend()
<matplotlib.legend.Legend at 0x25fff8b8a90>