第一章 感知机

1. 题目分析

已知训练数据集D,其正实例点是$x_1 = (3, 3)$,$x_2 = (4, 3)$, 负实例点是$x_3 = (1, 1)^T$,求感知机模型

  • 输入:训练数据集$T = \left\{(x_1, 1), (x_2, 1), (x_3, 1)\right\}$;学习率$\eta(0 < \eta \leq1)$;
  • 输出:w, b;感知机模型$f(x) = sign(w\cdot{x} + b)$.
    • 选取初值$w_0, b_0$
    • 在训练集中选取数据$(x_i, y_i)$
    • 如果$y_i(w\cdot{x} + b) \leq 0$
      • $w \leftarrow w + \eta{y_ix_i}$
      • $b \leftarrow b + \eta{y_i}$
    • 转至(2),直至训练集中没有误分类点

直观上的解释:当一个实例点被误分类,即位于分离超平面的错误一侧时,则调整w和b,使得分离超平面向该误分类点的一侧移动,以减少该误分类点与超平面间的距离,直至超平面越过该误分类点使其被正确分类。

2. 算法分析

感知机完整算法请走传送门,下面将拆解分析

2.1 初始化

# 定义数据集

data = np.array([[3, 3, 1],
                 [4, 3, 1],
                 [1, 1, -1]])

rows = data.shape[0]
cols = data.shape[1]
  • 将训练数据存储为2行3列的array,最后一列是每条数据的标签
  • 分别得到矩阵的行数rows和列数cols,为后续遍历做准备
# 选取初值w0, b0

w = np.ones(cols - 1)
b = 0
thea = 0.001
  • 初始化$w_0 = (1, 1)$,$b = 0$
  • 初始化$theta$,用于图示超平面,会在下面讲解

2.2 判断条件

# 方法:判别是否存在分类错误的点

def sign(data, w, b):
    flag = False

    rows = data.shape[0]
    cols = data.shape[1]

    for row in np.arange(rows):
        x_i = data[row, :-1]
        y_i = data[row, -1]

        if y_i * (np.matmul(w, x_i.T) + b) <= 0: flag="True" break return < code>
  • 对应算法中的第(3)步,筛选数据集中是否存在样本,使得$y_i(w\cdot{x} + b) \leq 0$成立
  • 设置$flag$变量,若为True则存在,若为False则不存在
  • 一旦发现不存在,马上跳出循环

2.3 图示超平面

# 方法:画散点图

def plot(data, w, b):
    plt.xlabel('x1')
    plt.ylabel('x2')
    plt.axis([0, 6, 0, 6])

    x = data[:, 0]
    y = data[:, 1]
    plt.scatter(x, y)

    x_line = [p for p in np.arange(10)]
    if w[1] == 0:
        y_line = [(-w[0]*x - b)/(w[1] + thea) for x in x_line]
    else:
        y_line = [(-w[0]*x - b)/w[1] for x in x_line]

    plt.plot(x_line, y_line)
  • 首先,定义好坐标轴的刻度,都控制在(0, 6)之间

  • 其次,先将数据集中的点画出来

  • 接着,根据当前的$w, b$值,选取$x_1, x_2$

    • $x_1$我们选定为(1, 10)中的整数

    • 根据$w_1x_1 + w_2x_2 + b = 0$,已知$x_1$,求得$x_2$如下

      $x_2 = \frac{-W_1x_1 - b}{w_2}$

    • 由于$w_2$可能为0,导致$x_2$求值出现问题,故我们加上一个$\theta$变量,一旦$w_2$为0, 则使得$x_2$为

      $x_2 = \frac{-W_1x_1 - b}{w_2 + \theta}$

  • 最后,画出超平面即可

2.4 遍历求解

# 遍历数据集

while sign(data, w, b):
    for row in np.arange(rows):
        x_i = data[row, :-1]
        y_i = data[row, -1]

        if y_i * (np.matmul(w, x_i.T) + b) <= 0: w="w" + y_i * x_i b="b" plot(data, w, b) < code>
  • 以$sign()$函数作为条件,判断有无误分类点,一旦有就遍历循环

    • 遍历每一条数据

      • 若是满足条件$y_i(w\cdot{x} + b) \leq 0$
      • 更新$w, b$
    • 将当前的超平面画出

      超平面

3. Sklearn实现

from sklearn.linear_model import Perceptron

# 1. 定义数据集
data = np.array([[3, 3, 1],
                 [4, 3, 1],
                 [1, 1, -1]])

# 2. 定义模型,求解
perceptron = Perceptron()
perceptron.fit(data[:, :2], data[:, 2])

# 3. 打印w,b,并图示
print("w: ", perceptron.coef_, "b: ", perceptron.intercept_)
plot(data, perceptron.coef_[0, :], perceptron.intercept_[0])

# 4. 测试模型准确率
res = perceptron.score(data[:, :2], data[:, 2])
print("correct rate:{:.0%}".format(res))