《Python 機器學習》筆記(二)


機器學習分類算法

本章將介紹最早以算法方式描述的分類機器學習算法:感知器(perceptron)和自適應線性神經元。

人造神經元——早期機器學習概覽

MP神經元

image

image

image

image

生物神經元和MP神經元模型的對應關系如下表:

image

image

這個結構非常簡單,如果你還記得前面所講的M-P神經元的結構的話,這個圖其實就是輸入輸出兩層神經元之間的簡單連接

單層感知器的局限性

雖然單層感知器簡單而優雅,但它顯然不夠聰明——它僅對線性問題具有分類能力。什么是線性問題呢?簡單來講,就是用一條直線可分的圖形。比如,邏輯“與”和邏輯“或”就是線性問題,我們可以用一條直線來分隔0和1。

1)邏輯“與”的真值表和二維樣本圖如圖2:

image

2)邏輯“或”的真值表如圖3:

這里寫圖片描述

為什么感知器就可以解決線性問題呢?這是由它的傳遞函數決定的。這里以兩個輸入分量 x1 和 x2 組成的二維空間為例,此時節點 j 的輸出為

image

所以,方程

image

確定的直線就是二維輸入樣本空間上的一條分界線。對於三維及更高維數的推導過程可以參考其他的Tutorials。

如果要讓它來處理非線性的問題,單層感知器網就無能為力了。例如下面的“異或”,就無法用一條直線來分割開來,因此單層感知器網就沒辦法實現“異或”的功能。

image

使用Python 實現感知器學習算法

Perceptron.py

import numpy as np
#eta是學習率  n_iter是迭代次數
#errors_是每個階段的錯誤數
#w_是權重吧
class Percetron(object):
    def __init__(self,eta=0.01,n_iter=10):
        self.eta=eta
        self.n_iter=n_iter
    def fit(self,X,y):
        self.w_=np.zeros(1+X.shape[1])#X的列數+1
        self.errors_=[]
        for _ in range(self.n_iter):#迭代次數
            errors=0
            for xi,target in zip(X,y):#將X,y組成
                update=self.eta*(target-self.predict(xi))#預測目標和實際目標是否相同
                self.w_[1:]+=update*xi#更新
                self.w_[0]+=update#更新b
                errors+=int(update != 0.0)#記錄這次迭代的錯誤數
            self.errors_.append(errors)
        return  self#關鍵返回參數W
    def net_input(self,X):#輸入X,輸出結果
        return np.dot(X,self.w_[1:])+self.w_[0]
    def predict(self,X):
        return np.where(self.net_input(X)>=0.0,1,-1)#如果結果大於等於0,返回1,否則返回0

main.py

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import Percetron as P
from matplotlib.colors import ListedColormap


def plot_decision_regions(X,y,classifier,resolution=0.02):#繪制決策邊界
    markers=('s','x','o','^','v')#標記
    colors=('red','blue','lightgreen','gray','cyan')#顏色
    cmap=ListedColormap(colors[:len(np.unique(y))])#定義一些顏色和標記符號,並通過顏色列表生成了顏色示例圖
    x1_min,x1_max=X[:,0].min()-1,X[:,0].max()+1#對最大值和最小值做出限定
    x2_min,x2_max=X[:,1].min()-1,X[:,1].max()+1
    xx1,xx2=np.meshgrid(np.arange(x1_min,x1_max,resolution),np.arange(x2_min,x2_max,resolution))
    Z=classifier.predict(np.array([xx1.ravel(),xx2.ravel()]).T)
    z=Z.reshape(xx1.shape)
    plt.xlim(xx1.min(),xx1.max())#x軸范圍
    plt.ylim(xx2.min(),xx2.max())#y軸范圍
    for idx,c1 in enumerate(np.unique(y)):
        plt.scatter(x=X[y==c1,0],y=X[y==c1,1],alpha=0.8,c=cmap(idx),marker=markers[idx],label=c1)






if __name__ == "__main__":
    df = pd.read_csv('https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data', header=None)
    df.tail()  # 用於顯示數據的最后五行以確保加載成功
    y=df.iloc[0:100,4].values#此時y是類別名稱
    y=np.where(y=='Iris-setosa',-1,1)#若是這個名稱則為-1,不是則為1
    X=df.iloc[0:100,[0,2]].values#從表中獲得X

    plt.scatter(X[:50,0],X[:50,1],color='red',marker='o',label='setosa')
    plt.scatter(X[50:100,0],X[50:100,1],color='blue',marker='x',label='versicolor')
    plt.xlabel('petal length')
    plt.ylabel('sepal length')
    plt.legend(loc='upper left')
    plt.show()

    ppn=P.Percetron(eta=0.1,n_iter=10)#初始化感知器
    ppn.fit(X,y)#擬合感知器
    plt.plot(range(1,len(ppn.errors_)+1),ppn.errors_,marker='o')#橫坐標從1到len(errors_),縱坐標為errors_,
    plt.xlabel('Epochs')
    plt.ylabel('Number of misclassifications')
    plt.show()


    plot_decision_regions(X,y,classifier=ppn)
    plt.xlabel('sepal length [cm]')
    plt.ylabel('petal length [cm]')
    plt.legend(loc='upper left')
    plt.show()


自適應線性神經元及其學習的收斂性

在之前的文章感知機中提到過,感知機分類器是一個非常好的二分類分類器。

但是感知機分類器仍然存在兩個比較明顯的缺陷:

  1. 感知機模型只能針對線性可分的數據集,對於非線性可分的數據集,無能為力
  2. 當兩個類可由線性超平面分離時,感知器學習規則收斂,但當類無法由線性分類器完美分離

為了解決感知機的這兩個主要的缺陷,就有了現在要講的自適應線性神經元

在之前的感知機中,感知機的激活函數是階躍函數,這里改為線性激活函數(linear activation function),一般來說,為了方便,可以直接取:

image

感知機框架和自適應線性神經元框架對比,注意,自適應線性神經元框架比感知機框架多了一個量化器(quantizer),其主要作用是得到樣本的類別。

image

梯度下降法(Gradient Descent)

相對於階躍函數而言,線性函數有一個明顯的優點:函數是可微(differentiable)的。這就使得我們可以直接在這個函數上定義損失函數 J(W)(cost function),並對其進行優化。這里定義損失函數J(W)為平方損失誤差和(SSE: sum of squared errors),這里假設訓練樣本集合的大小為n :

image

image

image

AdalineGD.py

import numpy as np
import matplotlib.pyplot as plt
import pandas as pd



class AdalineGD(object):
    def __init__(self,eta=0.01,n_iter=50):
        self.eta=eta
        self.n_iter=n_iter
    def fit(self,X,y):
        self.w_=np.zeros(1+X.shape[1])
        self.cost_=[]
        for i in range(self.n_iter):
            output=self.net_input(X)
            errors=(y-output)
            self.w_[1:]+=self.eta*X.T.dot(errors)
            self.w_[0]+=self.eta*errors.sum()
            cost=(errors**2).sum()/2
            self.cost_.append(cost)
        return self
    def net_input(self,X):
        return np.dot(X,self.w_[1:])+self.w_[0]
    def activation(self,X):
        return self.net_input(X)
    def predict(self,X):
        return np.where(self.activation(X)>=0,1,-1)
if __name__ == "__main__":
    df = pd.read_csv('https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data', header=None)
    df.tail()  # 用於顯示數據的最后五行以確保加載成功
    y = df.iloc[0:100, 4].values  # 此時y是類別名稱
    y = np.where(y == 'Iris-setosa', -1, 1)  # 若是這個名稱則為-1,不是則為1
    X = df.iloc[0:100, [0, 2]].values  # 從表中獲得X
    fig,ax=plt.subplots(nrows=1,ncols=2,figsize=(8,4))
    ada1=AdalineGD(n_iter=10,eta=0.01).fit(X,y)
    ax[0].plot(range(1,len(ada1.cost_)+1),np.log10(ada1.cost_),marker='o')
    ax[0].set_xlabel('Epochs')
    ax[0].set_ylabel('log(Sum-squared-error)')
    ax[0].set_title('Adaline-Learning rate 0.01')
    ada2=AdalineGD(n_iter=10,eta=0.0001).fit(X,y)
    ax[1].plot(range(1,len(ada2.cost_)+1),ada2.cost_,marker='o')
    ax[1].set_xlabel('Epochs')
    ax[1].set_ylabel('Sum-squared-error')
    ax[1].set_title('Adaline-Learning rate 0.0001')
    plt.show()


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM