模式识别——判别函数及几何分类法

前言

本篇博客对模式识别中的“判别函数与几何分类法”进行了讨论,并重点实现了最小平方误差法(Least Mean Square Error, LMSE)算法,也对不同的多类判别法、分段线性判别法进行了一定的实现,并通过随机生成的数据集加以测试。

项目源码及所使用的数据集参见:PR-EXPT2


基础知识

我们首先了解判别函数与几何分类法的基本知识,在此目中不追求科学语言的精确性,旨在用形式化的表达阐述其大致的思想。

判别函数与几何分类

1

上图呈现了典型的几何分类法的特点,其中左侧为线性判别法,右侧为非线性判别法,蓝色的直线与绿色的圆圈就称为判别函数。

判别函数

若将二维模式推广至n维,则线性判别函数的一般形式为:

2

其中,X为增广模式向量,W为增广权向量。

我们以两类情况为例,对于模式在w1w2中的两类情况,线性判别法的判别方式为:

3

d(X) = 0时,为不可判别情况。

至此,我们已经知道了用判别函数来进行几何分类法的整个过程,即:

  • 得到判别函数d(X):即求出增广权向量W
  • 用判别函数进行识别:对于一个待测模式X',我们能够用判别函数进行相应判别.

上述过程的第二步:“用判别函数进行识别”是非常简单的,只需要做两个矩阵的乘法运算。关键是第一步,我们该怎么得到判别函数呢,即该怎么求这个W呢?

可以很直观的想到,判别函数一定是通过训练得到的,即用已有的、已知其所属类别的模式,学习得到的。

不妨假设对已知的w_k类来说,这个类里面有X1, X2, ..., Xn这n个模式,那么我们所要求解的W,首先一定是要满足W * Xi > 0 (i = 1, 2, ..., n)这个不等式组的。除此之外,还需要满足什么额外条件呢?

而这些额外条件,恰恰是与我们的类别数有关的。

二分类

如果整个模式集只有两类,w1w2,假设这两个类的判别函数分别为d1(X)d2(X),那么如果一个模式X0属于w1类,就需要满足:

  • d1(X0) > 0,即这个模式在第一类里
  • d2(X0) < 0,即这个模式不在第二类里

那么再回到我们刚才讨论的“额外条件”问题:

假设w1类里有模式X1_1, X1_2, ..., X1_nw2类有模式X2_1, X2_2, ..., X2_n,那么对于判别函数d1的训练,我们首先需要:

d1(X1_i) > 0 (i = 1, 2, ..., n)

其次,还需要满足额外条件:d1(X2_i) < 0,即:

d1(- X2_i) > 0 (i = 1, 2, ..., n)

多分类

那么现在如果模式集有多类,额外条件又该如何确定呢?

在这里我们介绍两种方法:

  1. i_non_i 两分法,或者“正负类”法,即对于类wi来说,我们把所有的模式集分为两种:一种是属于wi的,另一种是不属于wi的。那么求解判别函数di(X)的不等式组为:

    di(Xi_j) > 0 (j = 1, 2, ..., n)

    di(- Xk_j) > 0 (j = 1, 2, ..., n; k为其他的模式类)

  2. i_j 两分法,即对于类wi与类wj来说,这就成了一个二分类的问题。因此,若假设总共有k个模式类,那么如果要把类wi与其他k-1个模式类区分开,就需要求解k-1个判别函数di_1, di_2, ..., di_k-1

    此时,到了”用判别函数进行识别”的时候,若模式X0属于wi类,就需要满足:di_j(X0) > 0,即对于以i打头的所有判别函数,其判别值均需为正。

线性分类算法

到了此处,我们已经明确了整个几何分类法的过程,也知道了在训练判别函数的时候,所要满足的不等式组是什么。那么这个不等式组又该如何求解呢?

这就涉及到了不同的线性分类算法。

虽然这些算法在形式上看起来十分复杂,但我们只需要记住一点:这些算法其实就是在解一个不等式方程组。

我们可以发散地想,这些算法甚至是独立于“模式识别”而存在的。假如你在线性代数的课堂上遇到了一道解不等式方程组的问题,就可以通过这些算法来解决它。其之所以应用在模式识别的领域上,只不过因为,模式识别的几何分类法需要解不等式方程组(即:求判别函数)。

下面我们列举了几种经典的线性分类算法。

  • 感知器算法
  • 梯度法
  • 最小平方误差算法

在实际应用中,我们应该明确这三种算法之间的关系:

  • 感知器算法是梯度法的一种特例。
  • 最小平方误差算法利用了梯度法。
  • 感知器算法与梯度算法在迭代运算时,算法有可能始终不收敛,因此在程序运行的过程中,我们无法得知,这究竟是因为迭代次数还不够,还是因为数据集本身的就线性不可分。而最小平方误差法改善了这一困境。

因此我们可以看到最小平方误差法的优势所在,本篇博客也主要实现了最小平方误差法。

分段线性判别法

在此我们简要介绍分段线性判别法的思想。

  • 分段线性判别法首先对已知类进行划分,将其分为父类和子类。
  • 我们需要训练出同一父类的子类之间的判别函数。
  • 对于某个待测模式,我们先用同一父类的各子类判别函数进行计算,并用效果最好的子类作为父类的判别函数。
  • 之后,我们再通过父类的判别函数,将待测模式划分到某一父类。

方案设计

实验要求

1、请实现以下功能之一
1)编写程序,使用感知器算法、梯度法和最小平方误差法中的一种算法,
训练线性判别函数并进行数据分类,分类时采用多分类情况的两种。

2)编写程序,使用感知器算法、梯度法和最小平方误差法中的两种算法,
训练线性判别函数并进行数据分类,分类时采用多分类情况的一种。

样本数据请自拟并不能少于30个数据样本,类别不少于5类。

其中部分样本用于训练判别函数,部分用于验证,并计算出正确率

2、请编写程序实现分段线性判别法进行数据分类。

样本数据请自拟并不能少于30个数据样本,类别不少于3类,每类至少有2个以上子类。

设计步骤

实验的实现共分为以下几个过程:

  1. 数据集的获取。在本实验中,随机生成了模式数据集。训练样本共分为6类,每类有8个模式;测试样本共分为6类,每类2个模式。

  2. 最小平方误差法(Least Mean Square Error, LMSE)算法的实现:

    最小平方误差算法(Least Mean Square Error, LMSE)
    (1)输入参数:规范化增广样本矩阵x
    (2)求X的伪逆矩阵 x# = (xT x)-1 xT
    (3)设置初值c和B(1)
    (4)计算e(k),并进行可分性判别
    (5)计算W(k+1)、B(k+1)
  3. 采用i_non_i 分类法训练判别函数,并评测识别正确率

  4. 采用i_j 分类法训练判别函数,并评测识别正确率

  5. 实现分段线性判别法,训练子类的判别函数,并评测识别正确率

实验环境

操作系统:MacOS X

开发语言:Python 2.7


具体实现

数据集生成

1

如上图所示,在[0, 50]的范围内随机生成模式集,并具体划分在0, 1, 2, 3, 4, 5 这6个类中。

具体实现如下:

# encoding:utf-8
# 生成数据集

import numpy as np


# 生成数据集
def gen_data_set(sample_size, class_size):
    x_k = []
    y_k = []

    for k in range(6):
        x = []
        y = []

        if k == 0:
            for i in range(sample_size):
                m = np.random.random() * 20
                n = np.random.random() * m
                x.append(m)
                y.append(n)

        if k == 1:
            for i in range(sample_size):
                m = np.random.random() * 30 + 20
                if m < 25:
                    n = np.random.random() * m
                else:
                    n = np.random.random() * ((-1) * m + 50)
                x.append(m)
                y.append(n)

        if k == 2:
            for i in range(sample_size):
                m = np.random.random() * 25 + 25
                n = np.random.random() * (2 * m - 50) + ((-1) * m + 50)
                x.append(m)
                y.append(n)

        if k == 3:
            for i in range(sample_size):
                m = np.random.random() * 30 + 20
                if m < 25:
                    n = np.random.random() * m + ((-1) * m + 50)
                else:
                    n = np.random.random() * (50 - m) + m
                x.append(m)
                y.append(n)

        if k == 4:
            for i in range(sample_size):
                m = np.random.random() * 20
                n = np.random.random() * m + ((-1) * m + 50)
                x.append(m)
                y.append(n)

        if k == 5:
            for i in range(sample_size):
                m = np.random.random() * 20
                n = np.random.random() * ((-2) * m + 50) + m
                x.append(m)
                y.append(n)

        # 记录坐标
        # for i in range(sample_size):
        #     print str(k) + "," + str(x[i]) + "," + str(y[i])

        x_k.append(x)
        y_k.append(y)

    return x_k, y_k


# 生成数据集并导入文件
def gen_data_to_file(train_file, test_file, class_size=6, train_set_size=10, test_set_size=5):
    train_sample_size = 8
    test_sample_size = 2
    train_x_k, train_y_k = gen_data_set(train_sample_size, class_size)
    test_x_k, test_y_k = gen_data_set(test_sample_size, class_size)

    # 数据集导入文件
    with open(train_file, 'w') as f:
        for i in range(class_size):
            for j in range(train_sample_size):
                f.write(str(i) + "," + str(train_x_k[i][j]) + "," + str(train_y_k[i][j]) + "\n")

    with open(test_file, 'w') as f:
        for i in range(class_size):
            for j in range(test_sample_size):
                f.write(str(i) + "," + str(test_x_k[i][j]) + "," + str(test_y_k[i][j]) + "\n")

并将生成的数据集导入文件。

最小平方误差法

# encoding:utf-8

import numpy as np
from numpy.linalg import inv


# 最小平方误差算法(Least Mean Square Error, LMSE)
# (1)输入参数:规范化增广样本矩阵x
# (2)求X的伪逆矩阵 x# = (xT x)-1 xT
# (3)设置初值c和B(1)
# (4)计算e(k),并进行可分性判别
# (5)计算W(k+1)、B(k+1)


def least_mean_square_error(data, b_1=0.1, c=1, k_n=100000):
    # x:规范化增广样本"矩阵"
    x = np.array(data, dtype=np.float64)
    x_sharp = inv(x.T.dot(x)).dot(x.T)
    row, col = x.shape

    # print x

    k = 1
    while k < k_n:
        if k % 10000 == 0:
            print "第" + str(k) + "次迭代..."

        if k == 1:
            # 设置初值B(1)
            b_k = (np.zeros(row) + b_1).T
            # b_k = x[:, 0]
            w_k = x_sharp.dot(b_k)
        else:
            b_k = b(k + 1, b_k, c, e_k)
            w_k = w(k + 1, w_k, c, x_sharp, e_k)

        # w_k = w(k+1, x_sharp, b_k)        # 方法二
        e_k = e(k + 1, x, w_k, b_k)

        if (e_k == 0).all():
            print "第" + str(k) + 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值