统计学习方法之感知机 python代码实现

感知机是二分类线性模型,其输入为实例的特征向量,输出为实例的类别,取+1和-1。

根据《统计学习方法》第2章,用python实现感知机。

import numpy as np
import matplotlib.pyplot as plt


class Perceptron:

    def __init__(self, dim):
        """ 初始化权重 w b 以及x特征的维度dim"""
        self.w = np.random.random((dim,))
        self.b = np.random.rand()
        self.dim = dim

    def f(self, x):
        """ w * x + b"""
        return np.dot(self.w, x.T) + self.b

    def gw(self, x, y):
        """ w梯度 """
        return x * y

    def gb(self,  y):
        """ b梯度"""
        return y

    def train_2(self, xs, ys, alpha=1, max_step=1000):
        """
        学习算法的对偶形式
        """

        n = len(xs)
        matrix = np.zeros((n,n),dtype=int)
        for i in range(n):
            for j in range(n):
                matrix[i][j] = np.dot(xs[i],xs[j])
        print("matrix:", matrix)
        a, b = [0]*n, 0
        step = 1
        error = float("inf")
        while error and step < max_step:
            print("step: {}, error: {}".format(step, error))
            error = 0
            for i,(x, y) in enumerate(zip(xs, ys)):
                sum_ = b
                for j in range(n):
                    sum_ += a[j]*ys[j]*matrix[j][i]
                if y*sum_ <= 0:
                    a[i] = a[i] + alpha
                    b += alpha * y
                    error += 1
            step += 1
        self.w = sum(a[i]*xs[i]*ys[i] for i in range(n))
        self.b = b
        if step >= max_step:
            print("max_step limit")
        else:
            print("successfully learn")
        print("w: {} b: {}".format(self.w, self.b))

    def train(self, xs, ys, alpha=0.1, max_step=1000):
        """
        学习算法
        :param xs: 输入样本特征
        :param ys: 样本分类
        :param alpha: 学习率
        :param max_step: 最大迭代伦次
        :return:
        """
        # 输入数据维度要等于指定维度(画图只能是二维)
        if xs.shape[1] != self.dim:
            raise ValueError("x sample must {} dim".format(self.dim))

        # 初始化图
        fig = self.figure_init(xs, ys)

        error = float("inf")
        step = 1
        while error and step < max_step:
            print("step: {}, error: {}".format(step, error))
            error = 0
            for x, y in zip(xs, ys):
                if self.f(x) * y <= 0:
                    self.w += alpha * self.gw(x, y)
                    self.b += alpha * self.gb(y)
                    self.figure_update(fig)  # 更新图
                    error += 1
            step += 1
        if step >= max_step:
            print("max_step limit")
        else:
            print("successfully learn")
        print("w: {} b: {}".format(self.w, self.b))

        # 关闭交互模式
        plt.ioff()

        # 图形显示
        plt.show()

    def figure_init(self, xs, ys):

        fig = plt.figure(figsize=(8, 6), dpi=80)
        ax = fig.add_subplot(1, 1, 1)
        # 设定标题等
        plt.title("Perceptron")
        plt.grid(True)

        # 设置X轴
        plt.xlabel("x(1)")
        plt.xlim(-10, 10)

        # 设置Y轴
        plt.ylabel("x(2)")
        plt.ylim(-10, 10)

        # 画点
        for x_, y_ in zip(xs, ys):
            if y_ == 1:
                ax.plot(x_[0], x_[1], "ro")
            else:
                ax.plot(x_[0], x_[1], "go")

        # 生成超平面 w1 * x1 + w2 * x2 + b = 0,随机取两个x1,计算x2连起来
        x1 = np.linspace(-10, 10, 2, endpoint=True)
        x2 = (- self.b - self.w[0] * x1) / self.w[1]

        # 画直线
        lines = ax.plot(x1, x2, "b-", linewidth=2.0, label="hyperplane")

        # 设置图例位置,loc可以为[upper, lower, left, right, center]
        ax.legend(loc="upper left", shadow=True)

        # 暂停
        plt.pause(0.5)

        ax.lines.remove(lines[0])
        # 打开交互模式
        plt.ion()

        return ax

    def figure_update(self, ax):
        """
        画图程序,每更新一次权重,调用一次
        """
        # 生成超平面 w1 * x1 + w2 * x2 + b = 0,随机取两个x1,计算x2连起来
        x1 = np.linspace(-10, 10, 2, endpoint=True)
        x2 = (- self.b - self.w[0]*x1)/self.w[1]

        # 更新直线
        lines = ax.plot(x1, x2, "b-", linewidth=2.0, label="hyperplane")
        # 暂停
        plt.pause(0.5)

        # 删掉直线
        ax.lines.remove(lines[0])


p = Perceptron(2)
x_data = np.array([[3, 3], [4, 3], [1, 1]])
y_data = np.array([1, 1, -1])
p.train(x_data, y_data)
# p.train_2(x_data, y_data)
其中,train函数是学习算法的原始形式,train_2是学习算法的对偶形式。其中error代表误分类的个数,简单的逻辑就是,当误分类的个数为0或者超出最大学习轮次则停止学习。
另外,figrue_init 和 figure_update函数则是在训练过程的图形展示。

你可能感兴趣的:(机器学习)