实现感知机

感知机

1 定义

假设输入空间(特征空间)是 χ ⊆ R n \chi\subseteq R^n χRn,输出空间是 Υ = { − 1 , + 1 } \Upsilon=\left\{-1,+1\right\} Υ={1,+1}。输入 x ∈ χ x\in\chi xχ 表示实例的特征向量,对应于输入空间(特征空间)的点;输出 y ∈ Υ y\in\Upsilon yΥ 表示实例的类别。由输入空间到输出空间的如下函数:
f ( x ) = s i g n ( ω ⋅ x + b ) f(x) = sign\left(\omega\cdot x + b\right) f(x)=sign(ωx+b)
称为感知机。 ω \omega ω b b b 为感知机模型参数。 ω ∈ R n \omega\in R^n ωRn 叫做权值(weight)或权值向量(weight vector), b ∈ R b\in R bR 叫做偏置(bias), ω ⋅ x \omega\cdot x ωx 表示 ω \omega ω x x x 的内积。 s i g n sign sign 是符号函数,即
s i g n ( x ) = { + 1 , x  ≥  0 − 1 , x  <  0 sign(x) = \begin{cases} +1, & \text{x $\ge$ 0} \\[2ex] -1, & \text{x $\lt$ 0} \end{cases} sign(x)=+1,1, 0< 0

从感知机算法的定义中可以看出, ω \omega ω b b b 是待求解参数,所以感知机算法的学习过程,就是求解 ω \omega ω b b b 的过程。

2 学习算法

输入:训练数据集 T = { ( x 1 , y 1 ) , ( x 2 , y 2 ) , ⋯   , ( x N , y N ) } T=\left\{\left(x_{1}, y_{1}\right),\left(x_{2}, y_{2}\right), \cdots,\left(x_{N}, y_{N}\right)\right\} T={(x1,y1),(x2,y2),,(xN,yN)},其中 x i ∈ χ = R n x_{i}\in\chi=R^n xiχ=Rn y i ∈ Υ = { − 1 , + 1 } y_{i}\in\Upsilon=\left\{-1,+1\right\} yiΥ={1,+1} i = 1 , 2 , ⋯   , N i=1,2,\cdots,N i=1,2,,N;学习率 η ( 0 < η ≤ 1 ) \eta\left(0<\eta\leq1\right) η(0<η1),又称为步长;

输出: ω , b \omega,b ω,b;感知机模型 f ( x ) = s i g n ( ω ⋅ x + b ) f(x) = sign(\omega\cdot x + b) f(x)=sign(ωx+b)

(1) 选取初始值 ω 0 , b 0 \omega_{0},b_{0} ω0,b0
(2) 在训练集中选取数据 ( x i , y i ) \left(x_{i},y_{i}\right) (xi,yi)
(3) 如果 y i ( ω ⋅ x i + b ) ≤ 0 y_{i}\left(\omega \cdot x_{i}+b\right)\leq0 yi(ωxi+b)0
   ω ← ω + η y i x i \omega\leftarrow \omega+\eta y_{i}x_{i} ωω+ηyixi
   b ← b + η y i b\leftarrow b+\eta y_{i} bb+ηyi
(4) 转至(2),直至训练集中没有误分类点

3 学习算法的代码实现

  1. 了解数据

    • 数据集T
      T = ( x 1 ( 1 ) x 1 ( 2 ) x 1 ( 3 ) ⋯ x 1 ( n ) y 1 x 2 ( 1 ) x 2 ( 2 ) x 2 ( 3 ) ⋯ x 2 ( n ) y 2 ⋮ ⋮ ⋮ ⋱ ⋮ ⋮ x N ( 1 ) x N ( 2 ) x N ( 3 ) ⋯ x N ( n ) y N ) T = \begin{pmatrix} x_1^{(1)}&x_1^{(2)}&x_1^{(3)}&\cdots&x_1^{(n)}&y_1\\[2ex] x_2^{(1)}&x_2^{(2)}&x_2^{(3)}&\cdots&x_2^{(n)}&y_2\\[2ex] \vdots&\vdots&\vdots&\ddots&\vdots&\vdots\\[2ex] x_N^{(1)}&x_N^{(2)}&x_N^{(3)}&\cdots&x_N^{(n)}&y_N\\[2ex] \end{pmatrix} T=x1(1)x2(1)xN(1)x1(2)x2(2)xN(2)x1(3)x2(3)xN(3)x1(n)x2(n)xN(n)y1y2yN

    • 样本 ( x i , y i ) \left(x_{i}, y_{i}\right) (xi,yi)
      ( x i , y i ) = ( x i ( 1 ) x i ( 2 ) x i ( 3 ) ⋯ x i ( n ) y i ) \left(x_{i}, y_{i}\right) = \begin{pmatrix} x_{i}^{(1)}&x_i^{(2)}&x_i^{(3)}&\cdots&x_i^{(n)}&y_i \\ \end{pmatrix} (xi,yi)=(xi(1)xi(2)xi(3)xi(n)yi)

  2. 初始化参数。在学习开始时,我们需要初始化参数的值,

    • ω \omega ω b b b 是待求解参数,无特殊要求,初始化时赋值为0即可;需要注意的是, ω \omega ω 是一个向量,而且是用来和样本 x i x_{i} xi 求内积的一个向量,所以 ω \omega ω 的维度和 x i x_{i} xi 相同,即等于样本的特征数。
      ω = ( ω 1 ω 2 ω 3 ⋯ ω n ) = ( 0 0 0 ⋯ 0 ) b = 0 \begin{array}{l} \omega = \begin{pmatrix} \omega_1&\omega_2&\omega_3&\cdots&\omega_n \end{pmatrix} = \begin{pmatrix} 0&0&0&\cdots&0\\ \end{pmatrix}\\ b = 0 \end{array} ω=(ω1ω2ω3ωn)=(0000)b=0

    • η \eta η 是一个超参数,可以灵活的调整,这里赋予一个默认值 1 。
      η = 1 \eta = 1 η=1

  3. 模型学习的过程,或者说参数求解的过程,可以简单概括为,循环选取样本,根据分类的正确与否,不断更新参数,直到所有样本分类正确(或满足提前设置的停止条件):

    • 循环选取样本,若样本分类错误,使用 η \eta η 更新参数 ω \omega ω b b b
      i f   y i ( ω ⋅ x i + b ) ≤ 0 ⇒ { ω ← ω + η y i x i b ← b + η y i if\ y_{i}\left(\omega \cdot x_{i}+b\right)\leq0 \Rightarrow \begin{cases} \omega\leftarrow \omega+\eta y_{i}x_{i}\\[2ex] b\leftarrow b+\eta y_{i} \end{cases} if yi(ωxi+b)0ωω+ηyixibb+ηyi

    • 所有样本被遍历完之后,若其中存在误分类的样本,重复上一步的操作。

梳理清算法的流程之后,我们就可以用代码来实现它:

# 初始化参数
w = np.zeros(X.shape[1])
b = 0
eta = 1
is_wrong = True

# 外层循环,必须保证所有样本都被分类正确,才会停止
while is_wrong:
    wrong_count = 0  # 分类错误的样本数
    index = 0  # 样本索引
    # 内层循环,依次遍历所有样本,并根据分类的正确与否,更新参数
    while index < X.shape[0]:
        # 使用索引选取样本
        xi = X[index]
        yi = y[index]
        # 判断:是否分类正确。
        if yi * (np.dot(w, xi) + b) <= 0:
            # 更新参数
            w = w + eta * np.dot(xi, yi)
            b = b + eta * yi
            # 对分类错误的样本进行计数
            wrong_count += 1
        # 选取下一个样本
        index += 1
    # 判断:是否所有样本都被正确分类
    if wrong_count == 0:
        is_wrong = False

4 模型预测

通过感知机的学习算法,我们最终可以求解出 ω \omega ω b b b 的值,对于新的样本,我们就能计算它们的标签。

f ( x ) = s i g n ( ω ⋅ x + b ) s i g n ( x ) = { + 1 , x  ≥  0 − 1 , x  <  0 f(x) = sign\left(\omega\cdot x + b\right)\\[3ex] sign(x) = \begin{cases} +1, & \text{x $\ge$ 0} \\[2ex] -1, & \text{x $\lt$ 0} \end{cases} f(x)=sign(ωx+b)sign(x)=+1,1, 0< 0

y_pre = np.array([1 if rst else -1 for rst in (np.dot(X, w) + b) >= 0])

5 代码封装

class Perceptron(object):
    '''
    Perceptron: the linear classification model of binary classification
    
    Parameters
    ----------
    max_iter : int, default=100
        Maximum number of misclassifications.
    eta : float, default=1
        Learning rate.
    verbose : bool, default=True
        The verbosity level
    '''
    
    def __init__(self,
                 max_iter=100,
                 eta=1,
                 verbose=True):
        self.max_iter_ = max_iter
        self.eta_ = eta
        self.w = 0
        self.b = 0
        self.verbose = verbose
        
        
    def fit(self, X, y):
        '''
        Fit linear model with Stochastic Gradient Descent.
        
        Parameters
        ----------
        X : {array-like, sparse matrix}, shape (n_samples, n_features)
            Training data.
        y : ndarray of shape (n_samples,)
            Target values.
        '''
        # 初始化w, b
        self.w = np.zeros(X.shape[1])
        self.b = 0

        # 停止条件: 样本误分次数
        ## 误分次数达到最大,或正确分类次数大于设定的误分次数
        n_iter = 0
        correct_count = 0
        while n_iter <= self.max_iter_:
            # 随机选取样本
            index = random.randint(0, X.shape[0] - 1)
            xi = X[index]
            yi = y[index]

            # 梯度下降
            if yi * (np.dot(self.w, xi) + self.b) <= 0:
                self.w += self.eta_ * np.dot(xi, yi)
                self.b += self.eta_ * yi
                n_iter += 1
                if self.verbose:
                    print(n_iter)
            else:
                correct_count += 1
                if correct_count > self.max_iter_:
                    break
                continue
                

    def predict(self, X):
        '''
        Predict class labels for samples in X.
        
        Parameters
        ----------
        X : array_like or sparse matrix, shape (n_samples, n_features)
            Samples.
        
        Returns
        -------
        C : array, shape [n_samples]
            Predicted class label per sample.
        '''
        # 计算标签
        rst = np.array([1 if rst else -1 for rst in (np.dot(X, self.w) + self.b) >= 0])
        # np.sign(0) == 0
        # rst = np.sign(np.dot(X, self.w) + self.b)
        return rst
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值