Python機(jī)器學(xué)習(xí)算法實(shí)現(xiàn) Author:louwill 今天筆者要實(shí)現(xiàn)的機(jī)器學(xué)習(xí)算法是感知機(jī)(perceptron)。感知機(jī)是一種較為簡(jiǎn)單的二分類模型,但由簡(jiǎn)至繁,感知機(jī)卻是神經(jīng)網(wǎng)絡(luò)和支持向量機(jī)的基礎(chǔ)。感知機(jī)旨在學(xué)習(xí)能夠?qū)⑤斎霐?shù)據(jù)劃分為+1/-1的線性分離超平面,所以說(shuō)整體而言感知機(jī)是一種線性模型。因?yàn)槭蔷€性模型,所以感知機(jī)的原理并不復(fù)雜,本節(jié)筆者就和大家來(lái)看一下感知機(jī)的基本原理和Python實(shí)現(xiàn)。 感知機(jī)原理 假設(shè)輸入x表示為任意實(shí)例的特征向量,輸出y={+1,-1}為實(shí)例的類別。感知機(jī)定義由輸入到輸出的映射函數(shù)如下: 其中sign符號(hào)函數(shù)為: w和b為感知機(jī)模型參數(shù),也是感知機(jī)要學(xué)習(xí)的東西。w和b構(gòu)成的線性方程wx+b=0極為線性分離超平面。 假設(shè)數(shù)據(jù)是線性可分的,當(dāng)然有且僅在數(shù)據(jù)線性可分的情況下,感知機(jī)才能奏效。感知機(jī)模型簡(jiǎn)單,但這也是其缺陷之一。所謂線性可分,也即對(duì)于任何輸入和輸出數(shù)據(jù)都存在某個(gè)線性超平面wx+b=0能夠?qū)?shù)據(jù)集中的正實(shí)例點(diǎn)和負(fù)實(shí)例點(diǎn)完全正確的劃分到超平面兩側(cè),這樣數(shù)據(jù)集就是線性可分的。 感知機(jī)的訓(xùn)練目標(biāo)就是找到這個(gè)線性可分的超平面。為此,定義感知機(jī)模型損失函數(shù)如下: 要優(yōu)化這個(gè)損失函數(shù),可采用梯度下降法對(duì)參數(shù)進(jìn)行更新以最小化損失函數(shù)。計(jì)算損失函數(shù)關(guān)于參數(shù)w和b的梯度如下: 由上可知完整的感知機(jī)算法包括參數(shù)初始化、對(duì)每個(gè)數(shù)據(jù)點(diǎn)判斷其是否誤分,如果誤分,則按照梯度下降法更新超平面參數(shù),直至沒(méi)有誤分類點(diǎn)。 以上便是感知機(jī)算法的基本原理。當(dāng)然這里說(shuō)的感知機(jī)僅限于單層的感知機(jī)模型,僅適用于線性可分的情況。對(duì)于線性不可分的情形,筆者將在后續(xù)的神經(jīng)網(wǎng)絡(luò)和感知機(jī)兩講詳細(xì)介紹。 感知機(jī)算法實(shí)現(xiàn) 完整的感知機(jī)算法包括參數(shù)初始化、模型主體、參數(shù)優(yōu)化等部分,我們便可以按照這個(gè)思路來(lái)實(shí)現(xiàn)感知機(jī)算法。在正式寫模型之前,我們先用sklearn來(lái)準(zhǔn)備一下示例數(shù)據(jù)。 # 導(dǎo)入相關(guān)庫(kù) import pandas as pd import numpy as np from sklearn.datasets import load_iris import matplotlib.pyplot as plt
# 導(dǎo)入iris數(shù)據(jù)集 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']
# 繪制散點(diǎn)圖 plt.scatter(df[:50]['sepal length'], df[:50]['sepal width'], c='red', label='0') plt.scatter(df[50:100]['sepal length'], df[50:100]['sepal width'], c='green', label='1') plt.xlabel('sepal length') plt.ylabel('sepal width') plt.legend();
下面正式開(kāi)始模型部分。先定義一個(gè)參數(shù)初始化函數(shù): # 定義參數(shù)初始化函數(shù) def initilize_with_zeros(dim): w = np.zeros(dim) b = 0.0 return w, b 然后定義sign符號(hào)函數(shù):
最后定義模型訓(xùn)練和優(yōu)化部分: # 定義感知機(jī)訓(xùn)練函數(shù) def train(X_train, y_train, learning_rate): # 參數(shù)初始化 w, b = initilize_with_zeros(X_train.shape[1]) # 初始化誤分類 is_wrong = False while not is_wrong: wrong_count = 0 for i in range(len(X_train)): X = X_train[i] y = y_train[i] # 如果存在誤分類點(diǎn) # 更新參數(shù) # 直到?jīng)]有誤分類點(diǎn) if y * sign(X, w, b) <= 0: w = w + learning_rate*np.dot(y, X) b = b + learning_rate*y wrong_count += 1 if wrong_count == 0: is_wrong = True print('There is no missclassification!') # 保存更新后的參數(shù) params = { 'w': w, 'b': b } return params 對(duì)示例數(shù)據(jù)進(jìn)行訓(xùn)練:
最后對(duì)訓(xùn)練結(jié)果進(jìn)行可視化,繪制模型的決策邊界: x_points = np.linspace(4, 7, 10) y_hat = -(params['w'][0]*x_points + params['b'])/params['w'][1] plt.plot(x_points, y_hat)
plt.plot(data[:50, 0], data[:50, 1], color='red', label='0') plt.plot(data[50:100, 0], data[50:100, 1], color='green', label='1') plt.xlabel('sepal length') plt.ylabel('sepal width') plt.legend() 最后,我們也可以建一個(gè)perceptron類來(lái)方便調(diào)用。對(duì)上述代碼進(jìn)行整理:
以上便是本節(jié)內(nèi)容。完整代碼文件和數(shù)據(jù)可參考我的GitHub地址: https://github.com/luwill/machine-learning-code-writing 參考資料: 李航 統(tǒng)計(jì)學(xué)習(xí)方法 https://github.com/fengdu78/lihang-code |
|
來(lái)自: LibraryPKU > 《機(jī)器學(xué)習(xí)》