python機器學習——感知器

最近在看機器學習相關的書籍,順便把天天閱讀的部分寫出來和你們分享,共同窗習探討一塊兒進步!做爲機器學習的第一篇博客,我準備從感知器開始,以後會慢慢更新其餘內容。python

在實現感知器算法前,咱們須要先了解一下神經元(neuron)的工做原理,神經元有不少樹突和一個軸突,樹突(Dendrites)能夠從其餘神經元接收信息並將其帶到細胞體(Cell nucleus),軸突(Axon)能夠從細胞體發送信息到其餘神經元。樹突傳遞過來的信息在細胞體中進行計算處理後,若是結果超過某個閾值,軸突會傳遞信號到其餘的神經元。人們經過認識神經元的工做過程,創造出了感知器學習算法。算法

感知器是Frank Rosenblatt在1975年就任於康奈爾實驗室時所發明的一種人工神經網絡,它被視爲一種最簡單形式的前饋神經網絡,是一種二元線性分類器,不足在於不能處理線性不可分問題。網絡

下圖爲三種不一樣狀況,左圖中的兩類能夠使用一條直線(即線性函數)分開,即線性可分;中間和右邊因爲不能使用線性函數分開,則爲線性不可分。app

咱們直接來看一個實例,假設咱們如今須要對花進行分類,數據集中有兩種花朵,分別將其記爲1和-1,咱們須要根據數據集含有的花的一些特徵來進行分類,這裏僅使用兩種花的特徵,即萼片長度和花瓣長度,將這兩個特徵用向量表示爲:
\[ x = \begin{bmatrix}x_1\\x_2\end{bmatrix} \]
x也叫作輸入向量,咱們再定義一個相應的權重向量w:
\[ w = \begin{bmatrix}w_1\\w_2\end{bmatrix} \]
將x和w線性組合後獲得z:
\[ z = w_1x_1+w_2x_2 \]
咱們假設,若是樣本的激活值z大於等於事先設置好的閾值b,咱們就說此樣本屬於類別1,不然屬於類別-1,公式表示以下:
\[ \phi(z) = \begin{cases}1,\quad z\ge b \\\\-1,\quad otherwise\end{cases} \]
能夠看出這個想法和神經元的工做原理很類似。爲了方便,咱們將閾值b移到等式的左邊並額外定義一個權重參數來代替-b,更新z爲如下等式:
\[ z = w_0x_0+w_1x_1+w_2x_2 \]
那麼上式中的z大於等於0的狀況也就等價於以前當z大於等於閾值b的狀況,能夠獲得:
\[ \phi(z) = \begin{cases}1,\quad z\ge0 \\\\-1,\quad otherwise\end{cases} \]
上面的函數也叫作激活函數,咱們經過激活函數將z壓縮到了一個二元輸出(1,-1),也就是:機器學習

咱們能夠看出權重向量w決定着分類是否準確,那麼咱們如何選擇合適的權重向量w呢?咱們不能一個一個給w賦值,這樣工做量太大且沒有效率,其實感知器能夠經過數據集中的樣本自動調整w,隨着訓練的進行,w的變化趨於平穩,分類的準確率也會大大提升。函數

咱們更新權重向量w的公式爲:
\[ w_j = w_j + \Delta w_j \]學習

\[ \Delta w_j = \eta(y^i-\hat{y^i})x^i_j \]spa

\[ \eta-學習率\\w_j-w向量的第j個特徵\\y^i-第i個樣本的真實類別\\\hat{y^i}-第i個樣本的預測類別\\x_j^i-第i個樣本的第j個特徵 \].net

其中學習率介於0.0和1.0之間,用於控制w更新的程度,權重向量w中的每個參數都是同步更新的,即只有在w的每一個參數的更新大小都計算出來後纔會改變w的值,咱們使用數據集中的大量訓練樣本x來更新w,來逐漸提升分類準確率。code

感知器算法只有類別線性可分且學習率較小的狀況下才能保證收斂,感知器接收訓練樣本x,將x與w線性結合獲得z,再將z傳遞給激活函數,產生一個分類結果做爲對樣本x的預測類別,以後按照更新規則來更新w,等收斂後感知器也就訓練完成了。

接下來咱們開始實現感知器算法並使用Iris數據集訓練:

import pandas as pd

讀取數據集

df = pd.read_csv('http://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data', header=None)
df.tail()
0 1 2 3 4
145 6.7 3.0 5.2 2.3 Iris-virginica
146 6.3 2.5 5.0 1.9 Iris-virginica
147 6.5 3.0 5.2 2.0 Iris-virginica
148 6.2 3.4 5.4 2.3 Iris-virginica
149 5.9 3.0 5.1 1.8 Iris-virginica

由上表能夠看到每一個輸入向量x都包含4個特徵(0、一、二、3)和1個正確的類別(4)

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

取出前100個訓練樣本的類別向量,若其類別輸入‘Iris-setosa’,則將其設置爲-1,不然設置爲1

y = df.iloc[0:100, 4].values
y = np.where(y == 'Iris-setosa', -1, 1)

取出前100個訓練樣本的前兩個特徵向量

X = df.iloc[0:100, [0, 2]].values

畫出這100個訓練樣本的類別分佈圖

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()

實現感知器

import numpy as np

class Perceptron(object):
    """Perceptron classifier.

    Parameters
    ----------
    eta:float
        Learning rate(between 0.0 and 1.0
    n_iter:int
        Passes over the training dataset.

    Attributes
    ----------
    w_:1d-array
        weights after fitting.
    errors_:list
        Number of miscalssifications in every epoch.

    """

    def __init__(self, eta=0.01, n_iter=10):
        self.eta = eta
        self.n_iter = n_iter

    def fit(self, X, y):
        """Fit training data.

        :param X:{array-like}, shape=[n_samples, n_features]
        Training vectors, where n_samples is the number of samples and
        n_features is the number of features.
        :param y: array-like, shape=[n_samples]
        Target values.
        :return:
        self:object

        """

        self.w_ = np.zeros(1 + X.shape[1]) # Add w_0
        self.errors_ = []

        for _ in range(self.n_iter):
            errors = 0
            for xi, target in zip(X, y):
                update = self.eta * (target - self.predict(xi))
                self.w_[1:] += update * xi
                self.w_[0] += update
                errors += int(update != 0.0)
            self.errors_.append(errors)
        return self

    def net_input(self, X):
        """Calculate net input"""
        return np.dot(X, self.w_[1:]) + self.w_[0]

    def predict(self, X):
        """Return class label after unit step"""
        return np.where(self.net_input(X) >= 0.0, 1, -1) #analoge ? :n in C++
ppn = Perceptron(eta = 0.1, n_iter = 10)
ppn.fit(X, y)
<__main__.Perceptron at 0x16680906978>

畫出訓練曲線

plt.plot(range(1, len(ppn.errors_) + 1), ppn.errors_, marker = 'o')
plt.xlabel('Epoches')
plt.ylabel('Number of misclassifications')
plt.show()

畫出分界線

from matplotlib.colors import ListedColormap
def plot_decision_region(X, y, classifier, resolution=0.02):
    # setup marker generator and color map
    markers = ('s', 'x', 'o', '^', 'v')
    colors = ('red', 'blue', 'lightgreen', 'gray', 'cyan')
    cmap = ListedColormap(colors[:len(np.unique(y))])
    
    # plot the decision surface
    x1_min, x1_max = X[:, 0].min() - 1, X[:, 0].max() + 1
    x2_min, x2_max = X[:, 1].min() - 1, X[:, 0].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.contourf(xx1, xx2, Z, alpha=0.4, cmap=cmap)
    plt.xlim(xx1.min(), xx1.max())
    plt.ylim(xx2.min(), xx2.max())
    
    #plot class samples
    for idx, cl in enumerate(np.unique(y)):
        plt.scatter(x=X[y == cl, 0], y=X[y == cl, 1],
                   alpha=0.8, c=cmap(idx), marker = markers[idx],
                   label=cl)
plot_decision_region(X, y, classifier=ppn)
plt.xlabel('sepal length [cm]')
plt.ylabel('petal length [cm]')
plt.legend(loc='upper left')
plt.show()

參考:

https://www.toutiao.com/a6669391886744027662/
https://zh.wikipedia.org/wiki/%E6%84%9F%E7%9F%A5%E5%99%A8

相關文章
相關標籤/搜索