通俗解释优化的线性感知机算法:Pocket PLA
個人網站:紅色石頭的機器學習之路
CSDN博客:紅色石頭的專欄
知乎:紅色石頭
微博:RedstoneWill的微博
GitHub:RedstoneWill的GitHub
微信公眾號:AI有道(ID:redstonewill)
在上一篇文章:
一看就懂的感知機算法PLA
我們詳細介紹了線性感知機算法模型,并使用pyhon實例,驗證了PLA的實際分類效果。下圖是PLA實際的分類效果:
但是,文章最后我們提出了一個疑問,就是PLA只能解決線性可分的問題。對于數據本身不是線性可分的情況,又該如何解決呢?下面,我們就將對PLA進行優(yōu)化,以解決更一般的線性不可分問題。
1. Pocket PLA是什么?
首先,我們來看一下線性不可分的例子:
如上圖所示,正負樣本線性不可分,無法使用PLA算法進行分類,這時候需要對PLA進行優(yōu)化。優(yōu)化后的PCA的基本做法很簡單,就是如果迭代更新后分類錯誤樣本比前一次少,則更新權重系數 w ;沒有減少則保持當前權重系數 w 不變。也就是說,可以把條件放松,即不苛求每個點都分類正確,而是容忍有錯誤點,取錯誤點的個數最少時的權重系數 w 。通常在有限的迭代次數里,都能保證得到最佳的分類線。
這種算法也被稱為「口袋PLA」Pocket PLA。怎么理解呢?就好像我們在搜尋最佳分類直線的時候,隨機選擇錯誤點修正,修正后的直線放在口袋里,暫時作為最佳分類線。然后如果還有錯誤點,繼續(xù)隨機選擇某個錯誤點修正,修正后的直線與口袋里的分類線比較,把分類錯誤點較少的分類線放入口袋。一直到迭代次數結束,這時候放在口袋里的一定是最佳分類線,雖然可能還有錯誤點存在,但已經是最少的了。
2. 數據準備
該數據集包含了100個樣本,正負樣本各50,特征維度為2。
data = pd.read_csv('./data/data2.csv', header=None) # 樣本輸入,維度(100,2) X = data.iloc[:,:2].values # 樣本輸出,維度(100,) y = data.iloc[:,2].values下面我們在二維平面上繪出正負樣本的分布情況。
import matplotlib.pyplot as pltplt.scatter(X[:50, 0], X[:50, 1], color='blue', marker='o', label='Positive') plt.scatter(X[50:, 0], X[50:, 1], color='red', marker='x', label='Negative') plt.xlabel('Feature 1') plt.ylabel('Feature 2') plt.legend(loc = 'upper left') plt.title('Original Data') plt.show()很明顯,從圖中可以看出,正類和負類樣本并不是線性可分的。這時候,我們就需要使用Pocket PLA。
3. Pocket PLA代碼實現
首先分別對兩個特征進行歸一化處理,即:
# 均值 u = np.mean(X, axis=0) # 方差 v = np.std(X, axis=0)X = (X - u) / v# 作圖 plt.scatter(X[:50, 0], X[:50, 1], color='blue', marker='o', label='Positive') plt.scatter(X[50:, 0], X[50:, 1], color='red', marker='x', label='Negative') plt.xlabel('Feature 1') plt.ylabel('Feature 2') plt.legend(loc = 'upper left') plt.title('Normalization data') plt.show()接下來對預測直線進行初始化,包括權重 w 初始化:
# X加上偏置項 X = np.hstack((np.ones((X.shape[0],1)), X)) # 權重初始化 w = np.random.randn(3,1)整個迭代訓練過程如下:
for i in range(100):s = np.dot(X, w)y_pred = np.ones_like(y)loc_n = np.where(s < 0)[0]y_pred[loc_n] = -1num_fault = len(np.where(y != y_pred)[0])if num_fault == 0:breakelse:r = np.random.choice(num_fault) # 隨機選擇一個錯誤分類點t = np.where(y != y_pred)[0][r]w2 = w + y[t] * X[t, :].reshape((3,1))s = np.dot(X, w2)y_pred = np.ones_like(y)loc_n = np.where(s < 0)[0]y_pred[loc_n] = -1num_fault2 = len(np.where(y != y_pred)[0])if num_fault2 <num_fault:w = w2 # 犯的錯誤點更少,則更新w,否則w不變其中,迭代次數為100次,每次迭代隨機選擇一個錯誤點進行修正,修正后的分類線錯誤率與之前的分類線比較,若錯誤率較低,則選擇修正后的分類線。繼續(xù)進行下一次迭代。
迭代完畢后,得到更新后的權重系數 w ,繪制此時的分類直線是什么樣子。
# 直線第一個坐標(x1,y1) x1 = -2 y1 = -1 / w[2] * (w[0] * 1 + w[1] * x1) # 直線第二個坐標(x2,y2) x2 = 2 y2 = -1 / w[2] * (w[0] * 1 + w[1] * x2) # 作圖 plt.scatter(X[:50, 1], X[:50, 2], color='blue', marker='o', label='Positive') plt.scatter(X[50:, 1], X[50:, 2], color='red', marker='x', label='Negative') plt.plot([x1,x2], [y1,y2],'r') plt.xlabel('Feature 1') plt.ylabel('Feature 2') plt.legend(loc = 'upper left') plt.show()計算一下分類的正確率:
s = np.dot(X, w) y_pred = np.ones_like(y) loc_n = np.where(s < 0)[0] y_pred[loc_n] = -1 accuracy = len(np.where(y == y_pred)[0]) / len(y) print('accuracy: %.2f' % accuracy) accuracy: 0.93分類正確率達到了0.93。
4. PLA的損失函數分析
我們知道,任何一個機器學習問題包含三個方面:模型、策略、算法。從策略來說,無論是PLA還是Pocket PLA,使用的損失函數是統(tǒng)計誤分類點的總數,即希望誤分類點的總數越少越好,屬于0-1損失函數「0-1 Loss Function」。但是,這樣的損失函數不是參數 w 的連續(xù)可導函數。
從算法實現上來看,PLA每次不斷修正錯誤點,修正公式為:
修正公式的推導,我們在上一篇文章中已經詳細解釋過。數學上可以證明,PLA算法是收斂的。
而對于分類問題,常見的損失函數一般為交叉熵損失函數「Cross Entropy Loss」。其表達式為:
交叉熵損失函數使用的梯度下降算法修正公式為:
對比起來,PLA和交叉熵損失函數的修正公式具有相似性,不同的是PLA沒有引入學習因子η和梯度。
以上內容對比了PLA和一般分類問題在策略和算法上的差異性。其實,紅色石頭想說的是,抓住本質最為重要,知道了不同的策略和方法,搭配不同的機器學習模型,只要能解決實際問題,都是可以的。也就是說我完全可以使用平方誤差來作為分類問題的策略,從理論上講是可行的。千萬不要在解決問題時,只固定一種思路。
5. 總結
PLA是機器學習最簡單的算法之一。PLA處理線性可分問題,優(yōu)化的PLA解決線性不可分的問題。實際驗證表明,一般的PLA處理線性可分及線性不可分問題都有不錯的表現,即一般能得到最佳的分類直線。但是PLA過于簡單,有其本身的局限性。
本文完整代碼我已上傳到GitHub上,需要的點擊「閱讀原文」自行獲取。喜歡的話,不妨點個Star。
P.S. 有興趣的讀者朋友也可以看看李航的《統(tǒng)計學習方法》第二章關于PLA的介紹,其思路和做法與我說的有所不同,使用的損失函數是誤分類點到超平面的距離,效果應該更好一些。
閱讀原文
更多干貨文章請關注公眾號:AI有道(ID:redstonewill)
總結
以上是生活随笔為你收集整理的通俗解释优化的线性感知机算法:Pocket PLA的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 女孩常用双关语--男生进
- 下一篇: 公众号质量改进调查问卷