基于感知机Perceptron的鸢尾花分类实践
生活随笔
收集整理的這篇文章主要介紹了
基于感知机Perceptron的鸢尾花分类实践
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
文章目錄
- 1. 感知機簡介
- 2. 編寫感知機實踐
- 2.1 數據處理
- 2.2 編寫感知機類
- 2.3 多參數組合運行
- 3. sklearn 感知機實踐
- 4. 附完整代碼
本文將使用感知機模型,對鳶尾花進行分類,并調整參數,對比分類效率。
1. 感知機簡介
感知機(perceptron)是二類分類的線性分類模型
- 輸入:實例的特征向量
- 輸出:實例的類別,取 +1 和 -1 二值
- 感知機對應于輸入空間(特征空間)中將實例劃分為正負兩類的分離超平面,屬于判別模型
- 旨在求出將訓練數據進行線性劃分的分離超平面,為此,導入基于誤分類的損失函數,利用梯度下降法對損失函數進行極小化,求得感知機模型。
- 感知機學習算法具有簡單而易于實現的優點,分為原始形式和對偶形式。
- 預測:對新的輸入進行分類
具體內容見李航《統計學習方法》第二章,感知機 讀書筆記。
2. 編寫感知機實踐
本文代碼參考了此處:fengdu78,本人添加了感知機算法的對偶形式,并對不同的參數下的迭代次數進行比較。
2.1 數據處理
- 數據采用sklearn內置的鳶尾花數據(數據介紹請參考此處)
2.2 編寫感知機類
class PerceptronModel():def __init__(self, X, y, eta):self.w = np.zeros(len(X[0]), dtype=np.float) # 權重self.b = 0 # 偏置self.eta = eta # 學習率self.dataX = X # 數據self.datay = y # 標簽self.iterTimes = 0 # 迭代次數# 對偶形式的參數self.a = np.zeros(len(X), dtype=np.float) # alphaself.Gmatrix = np.zeros((len(X), len(X)), dtype=np.float)self.calculateGmatrix() # 計算Gram矩陣def sign0(self, x, w, b): # 原始形式sign函數y = np.dot(w, x) + breturn ydef sign1(self, a, G_j, Y, b): # 對偶形式sign函數y = np.dot(np.multiply(a, Y), G_j) + breturn ydef OriginClassifier(self): # 原始形式的分類算法self.iterTimes = 0self.b = 0stop = Falsewhile not stop:wrong_count = 0for i in range(len(self.dataX)):X = self.dataX[i]y = self.datay[i]if (y * self.sign0(X, self.w, self.b)) <= 0:self.w += self.eta * np.dot(X, y)self.b += self.eta * ywrong_count += 1self.iterTimes += 1if wrong_count == 0:stop = Trueprint("原始形式,分類完成!步長:%.4f, 共迭代 %d 次" % (self.eta, self.iterTimes))def calculateGmatrix(self): # 計算Gram矩陣for i in range(len(self.dataX)):for j in range(0, i + 1): # 對稱的計算一半就行self.Gmatrix[i][j] = np.dot(self.dataX[i], self.dataX[j])self.Gmatrix[j][i] = self.Gmatrix[i][j]def DualFormClassifier(self): # 對偶形式分類算法self.iterTimes = 0self.b = 0stop = Falsewhile not stop:wrong_count = 0for i in range(len(self.dataX)):y = self.datay[i]G_i = self.Gmatrix[i]if (y * self.sign1(self.a, G_i, self.datay, self.b)) <= 0:self.a[i] += self.etaself.b += self.eta * ywrong_count += 1self.iterTimes += 1if wrong_count == 0:stop = Trueprint("對偶形式,分類完成!步長:%.4f, 共迭代 %d 次" % (self.eta, self.iterTimes))2.3 多參數組合運行
# 調用感知機進行分類,學習率etaperceptron = PerceptronModel(X, y, eta=0.3)perceptron.OriginClassifier() # 原始形式分類# 繪制原始算法分類超平面x_points = np.linspace(4, 7, 10)y0 = -(perceptron.w[0] * x_points + perceptron.b) / perceptron.w[1]plt.plot(x_points, y0, 'r', label='原始算法分類線')perceptron.DualFormClassifier() # 對偶形式分類# 由alpha,b 計算omega向量omega0 = sum(perceptron.a[i] * y[i] * X[i][0] for i in range(len(X)))omega1 = sum(perceptron.a[i] * y[i] * X[i][1] for i in range(len(X)))y1 = -(omega0 * x_points + perceptron.b) / omega1# 繪制對偶算法分類超平面plt.plot(x_points, y1, 'b', label='對偶算法分類線')plt.rcParams['font.sans-serif'] = 'SimHei' # 消除中文亂碼plt.legend()plt.show()| η=0.1\eta=0.1η=0.1 | 初值全0,迭代1518次,初值全1,迭代1473次 | 初值全0,迭代1488次,初值全1,迭代2378次 |
| η=0.5\eta=0.5η=0.5 | 初值全0,迭代1562次,初值全1,迭代1472次 | 初值全0,迭代1518次,初值全1,迭代1325次 |
| η=1\eta=1η=1 | 初值全0,迭代1562次,初值全1,迭代1486次 | 初值全0,迭代1518次,初值全1,迭代1367次 |
結論:
- 感知機的兩種算法形式均會因為初值和學習率的不同,而造成的多種迭代路徑
- 從上面圖標也印證了,對于線性可分的數據,感知機學習算法迭代是收斂的
3. sklearn 感知機實踐
sklearn.linear_model.Perceptron 官網參數介紹
class sklearn.linear_model.Perceptron(penalty=None, alpha=0.0001, fit_intercept=True, max_iter=1000, tol=0.001, shuffle=True, verbose=0, eta0=1.0, n_jobs=None, random_state=0, early_stopping=False,validation_fraction=0.1, n_iter_no_change=5, class_weight=None, warm_start=False) classify = Perceptron(fit_intercept=True, max_iter=1000, shuffle=True, eta0=0.1, tol=None) classify.fit(X, y) print("特征權重:", classify.coef_) # 特征權重 w print("截距(偏置):", classify.intercept_) # 截距 b# 可視化 plt.scatter(df[:50][iris.feature_names[0]], df[:50][iris.feature_names[1]], label=iris.target_names[0]) plt.scatter(df[50:100][iris.feature_names[0]], df[50:100][iris.feature_names[1]], label=iris.target_names[1]) plt.xlabel(iris.feature_names[0]) plt.ylabel(iris.feature_names[1])# 繪制分類超平面 x_points = np.linspace(4, 7, 10) y = -(classify.coef_[0][0] * x_points + classify.intercept_) / classify.coef_[0][1] plt.plot(x_points, y, 'r', label='sklearn Perceptron分類線')plt.title("sklearn內置感知機分類") plt.legend() plt.show()運行結果:
特征權重: [[ 6.95 -8.73]] 截距(偏置): [-11.2]- 可以看出在這兩個特征下,兩種花線性可分,感知機將兩類花分類成功
我們稍微更改下數據為后兩種花,再次運行
- 可以看出,后兩種花在這2個特征下線性不可分,感知機做出了錯誤分類線
4. 附完整代碼
# -*- coding:utf-8 -*- # @Python 3.7 # @Time: 2020/2/28 22:07 # @Author: Michael Ming # @Website: https://michael.blog.csdn.net/ # @File: 2.perceptron.py # @Reference: https://github.com/fengdu78/lihang-codeimport pandas as pd import numpy as np from sklearn.datasets import load_iris from sklearn.linear_model import Perceptron import matplotlib.pyplot as pltclass PerceptronModel():def __init__(self, X, y, eta):self.w = np.zeros(len(X[0]), dtype=np.float) # 權重self.b = 0 # 偏置self.eta = eta # 學習率self.dataX = X # 數據self.datay = y # 標簽self.iterTimes = 0 # 迭代次數# 對偶形式的參數self.a = np.zeros(len(X), dtype=np.float) # alphaself.Gmatrix = np.zeros((len(X), len(X)), dtype=np.float)self.calculateGmatrix() # 計算Gram矩陣def sign0(self, x, w, b): # 原始形式sign函數y = np.dot(w, x) + breturn ydef sign1(self, a, G_j, Y, b): # 對偶形式sign函數y = np.dot(np.multiply(a, Y), G_j) + breturn ydef OriginClassifier(self): # 原始形式的分類算法self.iterTimes = 0self.b = 0stop = Falsewhile not stop:wrong_count = 0for i in range(len(self.dataX)):X = self.dataX[i]y = self.datay[i]if (y * self.sign0(X, self.w, self.b)) <= 0:self.w += self.eta * np.dot(X, y)self.b += self.eta * ywrong_count += 1self.iterTimes += 1if wrong_count == 0:stop = Trueprint("原始形式,分類完成!步長:%.4f, 共迭代 %d 次" % (self.eta, self.iterTimes))def calculateGmatrix(self): # 計算Gram矩陣for i in range(len(self.dataX)):for j in range(0, i + 1): # 對稱的計算一半就行self.Gmatrix[i][j] = np.dot(self.dataX[i], self.dataX[j])self.Gmatrix[j][i] = self.Gmatrix[i][j]def DualFormClassifier(self): # 對偶形式分類算法self.iterTimes = 0self.b = 0stop = Falsewhile not stop:wrong_count = 0for i in range(len(self.dataX)):y = self.datay[i]G_i = self.Gmatrix[i]if (y * self.sign1(self.a, G_i, self.datay, self.b)) <= 0:self.a[i] += self.etaself.b += self.eta * ywrong_count += 1self.iterTimes += 1if wrong_count == 0:stop = Trueprint("對偶形式,分類完成!步長:%.4f, 共迭代 %d 次" % (self.eta, self.iterTimes))if __name__ == '__main__':# 讀取鳶尾花數據iris = load_iris()# 將鳶尾花4個特征,以4列存入pandas的數據框架df = pd.DataFrame(iris.data, columns=iris.feature_names)# 在最后一列追加 加入標簽(分類)列數據df['lab'] = iris.target# df.columns=[iris.feature_names[0], iris.feature_names[1], iris.feature_names[2], iris.feature_names[3], 'lab']# df['lab'].value_counts()# 選取前兩種花進行劃分(每種數據50組)plt.scatter(df[:50][iris.feature_names[0]], df[:50][iris.feature_names[1]], label=iris.target_names[0])plt.scatter(df[50:100][iris.feature_names[0]], df[50:100][iris.feature_names[1]], label=iris.target_names[1])plt.xlabel(iris.feature_names[0])plt.ylabel(iris.feature_names[1])# 選取數據,前100行,前兩個特征,最后一列標簽data = np.array(df.iloc[:100, [0, 1, -1]])# X是除最后一列外的所有列,y是最后一列X, y = data[:, :-1], data[:, -1]# 生成感知機的標簽值,+1, -1, 第一種-1,第二種+1y = np.array([1 if i == 1 else -1 for i in y])# 調用感知機進行分類,學習率etaperceptron = PerceptronModel(X, y, eta=0.1)perceptron.OriginClassifier() # 原始形式分類# 繪制原始算法分類超平面x_points = np.linspace(4, 7, 10)y0 = -(perceptron.w[0] * x_points + perceptron.b) / perceptron.w[1]plt.plot(x_points, y0, 'r', label='原始算法分類線')perceptron.DualFormClassifier() # 對偶形式分類# 由alpha,b 計算omega向量omega0 = sum(perceptron.a[i] * y[i] * X[i][0] for i in range(len(X)))omega1 = sum(perceptron.a[i] * y[i] * X[i][1] for i in range(len(X)))y1 = -(omega0 * x_points + perceptron.b) / omega1# 繪制對偶算法分類超平面plt.plot(x_points, y1, 'b', label='對偶算法分類線')plt.rcParams['font.sans-serif'] = 'SimHei' # 消除中文亂碼plt.legend()plt.show()# ------------------學習率不同,查看迭代次數----------------------------n = 5i = 0eta_iterTime = np.zeros((n, 3), dtype=float)for eta in np.linspace(0.01, 1.01, n):eta_iterTime[i][0] = eta # 第一列,學習率perceptron = PerceptronModel(X, y, eta)perceptron.OriginClassifier()eta_iterTime[i][1] = perceptron.iterTimes # 第二列,原始算法迭代次數perceptron.DualFormClassifier()eta_iterTime[i][2] = perceptron.iterTimes # 第三列,對偶算法迭代次數i += 1x = eta_iterTime[:, 0] # 數據切片y0 = eta_iterTime[:, 1]y1 = eta_iterTime[:, 2]plt.scatter(x, y0, c='r', marker='o', label='原始算法')plt.scatter(x, y1, c='b', marker='x', label='對偶算法')plt.xlabel('步長(學習率)')plt.ylabel('迭代次數')plt.title("不同步長,不同算法形式下,迭代次數")plt.legend()plt.show()# ------------------sklearn實現----------------------------classify = Perceptron(fit_intercept=True, max_iter=10000, shuffle=False, eta0=0.5, tol=None)classify.fit(X, y)print("特征權重:", classify.coef_) # 特征權重 wprint("截距(偏置):", classify.intercept_) # 截距 b# 可視化plt.scatter(df[:50][iris.feature_names[0]], df[:50][iris.feature_names[1]], label=iris.target_names[0])plt.scatter(df[50:100][iris.feature_names[0]], df[50:100][iris.feature_names[1]], label=iris.target_names[1])plt.xlabel(iris.feature_names[0])plt.ylabel(iris.feature_names[1])# 繪制分類超平面x_points = np.linspace(4, 7, 10)y = -(classify.coef_[0][0] * x_points + classify.intercept_) / classify.coef_[0][1]plt.plot(x_points, y, 'r', label='sklearn Perceptron分類線')plt.title("sklearn內置感知機分類")plt.legend()plt.show() 創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的基于感知机Perceptron的鸢尾花分类实践的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 剑指Offer - 面试题36. 二叉搜
- 下一篇: LintCode 386. 最多有k个不