近邻分类器的设计

目录

一、实验内容及要求

二、实验原理及代码

1.近邻法原理及其决策规则

2.k-近邻法决策规则

3.剪辑近邻法

4.压缩近邻法


一、实验内容及要求

1.使用IRIS数据集,每个类别选45个训练样本,5个测试样本,分别用最近邻法、k近邻法对测试样本进行分类,比较分类错误率;

2.调整k的值,比较不同的k值对错误率的影响.

3.采用剪辑近邻法和压缩近邻法对训练数据进行处理,用优化后的训练样本集对测试集进行分类,比较分类错误率

4.使用python实现

二、实验原理及代码

1.近邻法原理及其决策规则

最小距离分类器:将各类训练样本划分成若干子类,并在每个子类中确定代表点测试样本的类别则以其与这些代表点距离最近作决策。该法的缺点:所选择的代表点并不一定能很好地代表各类,其后果将使错误率增加。

以全部训练样本作为“代表点”,计算测试样本与这些“代表点”,即所有样本的距离,并以最近邻者的类别作为决策。

最近邻法决策规则:将与测试样本最近邻样本的类别作为决策的方法称为最近邻法。

对一个C类别问题,每类有Ni个样本,i=1,…,C,则第i类ωi的判别函数

判别函数的决策规则:

若: ;则:X∈ωj

表示是ωi类的第k个样本

代码如下:

import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt

def pplt(df, test_point=[0, 0], flag=0):
    fig = plt.figure()
    ax = fig.gca(projection='3d')

    ax.scatter(df[:45, 0], df[:45, 1], df[:45, 2], c='r', label="points 1")
    ax.scatter(df[45:90, 0], df[45:90, 1], df[45:90, 2], c='g', label="points 2")
    ax.scatter(df[90:135, 0], df[90:135, 1], df[90:135, 2], c='b', label="points 3")

    if flag == 1:
        ax.scatter(test_point[0], test_point[1], test_point[2], c='black', label='test_point')

    plt.legend()
    plt.show()

class MNN():
    def __init__(self, X_train, y_train, p=2):
        '''
        self:类名
        X_train:训练样本
        y_train:训练样本标签数组
        p=2:二维 范数为2  根下平方和
        '''
        self.p = p
        self.X_train = X_train
        self.y_train = y_train

    def predict(self, X): # X 为测试样本的data  1*3
        knn_list = []
        # print('X:',X)
        dist = np.linalg.norm(X - self.X_train[0], ord=self.p) # 求范数   即求距离
        knn_list.append((dist, self.y_train[0]))   # 列表里放  (距离,下标)的元组

        for i in range(len(self.X_train)):
            dist = np.linalg.norm(X - self.X_train[i], ord=self.p)
            if knn_list[0][0] > dist: # knn_list[max_index][0]中距离最大的
                knn_list[0] = (dist, self.y_train[i])

        return knn_list[0][1]

    def score(self, X_test, y_test):
        right_count = 0

        for X, y in zip(X_test, y_test):# zip() 函数用于将可迭代对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的对象。 X_test,取第一行数据
            label = self.predict(X)
            print('predict lable',label)
            if label == y:
                right_count += 1
        return right_count / len(X_test)



if __name__=="__main__":
    f_train1 = np.loadtxt("..\\iris训练数据.txt", dtype=np.double, delimiter='\t', usecols=[0, 1, 2, 3])  # 使用第123个特征
    f_train2 = np.loadtxt("..\\iris测试数据.txt", dtype=np.double, delimiter='\t', usecols=[0, 1, 2, 3])

    train = (np.r_[f_train1[0:25,], f_train2[0:20], f_train1[25:50], f_train2[25:45], f_train1[50:75], f_train2[50:70]]) # 135* 4 里面np.r 是元组 转置后是矩阵
    test = (np.r_[f_train2[20:25], f_train2[45:50], f_train2[70:75]])  # 测试样本 15*4
    # print(test[0, :])

    clf = MNN(train[:, 1:4], train[:, 0])

    print(clf.score(test[:, 1:4], test[:, 0]))
    test_point = [6.0, 3.0, 2.0]
    print('Test Point:{}'.format(clf.predict(test_point)))

    pplt(train, test_point, flag=1)

2.k-近邻法决策规则

    在所有N个样本中找到与测试样本的k个最近邻者,其中各类别所占个数表示成ki,i=1,…,c。

则决策规划是:

如果:

则:X∈ωj  

实验代码

import numpy as np
import matplotlib.pyplot as plt
from collections import Counter
from mpl_toolkits.mplot3d import Axes3D


def pplt(df, test_point=[0, 0], flag=0):
    fig = plt.figure()
    ax = fig.gca(projection='3d')

    ax.scatter(df[:45, 0], df[:45, 1], df[:45, 2], c='r', label="points 1")
    ax.scatter(df[45:90, 0], df[45:90, 1], df[45:90, 2], c='g', label="points 2")
    ax.scatter(df[90:135, 0], df[90:135, 1], df[90:135, 2], c='b', label="points 3")

    if flag == 1:
        ax.scatter(test_point[0], test_point[1], test_point[2], c = 'black', label='test_point')

    plt.legend()
    plt.show()


class KNN():
    def __init__(self, X_train, y_train, n_neighbors=3, p=2):
        '''
        self:类名
        X_train:样本
        y_train:样本标签数组
        n_neighbors=3:k近邻中的K 此处为3
        p=2:二维 范数为2  根下平方和
        '''
        self.n = n_neighbors
        self.p = p
        self.X_train = X_train
        self.y_train = y_train

    def predict(self, X):
        knn_list = []

        for i in range(self.n):
            dist = np.linalg.norm(X - self.X_train[i], ord=self.p)  # 求范数   即求距离
            knn_list.append((dist, self.y_train[i]))

        for i in range(self.n, len(self.X_train)):
            max_index = knn_list.index(max(knn_list, key=lambda x: x[0]))  # knn_list中距离最大的取其下标
            dist = np.linalg.norm(X - self.X_train[i], ord=self.p)
            if knn_list[max_index][0] > dist:  # knn_list[max_index][0]中距离最大的
                knn_list[max_index] = (dist, self.y_train[i])
        knn = [k[-1] for k in knn_list]  # 把计算的k近邻的标签计入knn
        count_pairs = Counter(knn)  # counter为计数器,按照标签计数
        max_count = sorted(count_pairs.items(), key=lambda x: x[1])[-1][0]
        return max_count

    def score(self, X_test, y_test):
        right_count = 0

        for X, y in zip(X_test, y_test):  # zip() 函数用于将可迭代对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的对象。
            label = self.predict(X)
            print('lable', label)
            if label == y:
                right_count += 1
        return right_count / len(X_test)


if __name__ == "__main__":
    f_train1 = np.loadtxt("..\\iris训练数据.txt", dtype=np.double, delimiter='\t', usecols=[0, 1, 2, 3])  # 使用第123个特征
    f_train2 = np.loadtxt("..\\iris测试数据.txt", dtype=np.double, delimiter='\t', usecols=[0, 1, 2, 3])

    train = (np.r_[f_train1[0:25, ], f_train2[0:20], f_train1[25:50], f_train2[25:45], f_train1[50:75], f_train2[
                                                                                                        50:70]])  # 135* 4 里面np.r 是元组 转置后是矩阵
    test = (np.r_[f_train2[20:25], f_train2[45:50], f_train2[70:75]])  # 测试样本 15*4
    # print(train.shape)

    clf = KNN(train[:, 1:4], train[:, 0],7)
    print(clf.score(test[:, 1:4], test[:, 0]))
    test_point = [6.0, 3.0, 5.0]
    print('Test Point 所属类别:{}'.format(clf.predict(test_point)))

    pplt(train[:, 1:4], test_point, flag=1)

3.剪辑近邻法

原理:从训练数据集中剔除两类交界处容易错分的样本,从而减少训练样本集,降低错误率。

步骤:

(1)将样本集X随机划分为多个子集合X={X1,X2,…,Xs};

(2)用最近邻法,X(i+1)mod(s) 作为训练集对集合Xi进行分类;

(3)去掉步骤(2)中被错分的样本;

(4)用所有留下的样本,构成新的样本集

(5)经过k次操作,若没有样本被剪辑掉则停止。

实验代码

# 两分剪辑近邻法
import numpy as np
from MNN import MNN
def clip(T_train, T_test,test):
    '''
    训练样本集分成两类 训练集 T_train 15*4 考试集 T_test 120*4
    利用训练集的样本对考试集的每个样本利用最近邻法进行分类决策,剪辑掉那些被训练集中样本错分类的样本,然后将考试集中剩余样本构成剪辑样本集。
    '''
    T_after = [] # 保存最终的训练样本集   (array([ 5.4,  3.9,  1.7]), 1.0)
    clf = MNN(T_train[:, 1:4], T_train[:, 0]) # 样本数据 对应标签
    for X, y in zip(T_test[:, 1:4], T_test[:, 0]):  # zip() 函数用于将可迭代对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的对象。 X_test,取第一行数据
        label = clf.predict(X)
        if label == y:
            T_after.append((X, y))
    # print(T_after[0][0]) # 104个
    # # pplt(train, test_point, flag=1)
    # T_after = np.matrix(T_after)
    X = T_after[0][0]
    y = T_after[0][1]
    # print(T)
    # T = np.c_[T,T_after[1][0]]
    # T = np.c_[T, T_after[2][0]]
    # print(T.T)
    for i in range(T_after.__len__()):
        if(i!=1):
            X = np.c_[X,T_after[i][0]]
            y = np.c_[y,T_after[i][1]]
    X = X.T #104*3
    y = y.T # 104*1
    # print(X)
    a = MNN(X,y)
    # print(a.y_train.shape)


    return a
if __name__=="__main__":
    f_train1 = np.loadtxt("..\\iris训练数据.txt", dtype=np.double, delimiter='\t', usecols=[0, 1, 2, 3])  # 使用第123个特征
    f_train2 = np.loadtxt("..\\iris测试数据.txt", dtype=np.double, delimiter='\t', usecols=[0, 1, 2, 3])
    # train = (np.r_[f_train1[0:25,], f_train2[0:20], f_train1[25:50], f_train2[25:45], f_train1[50:75], f_train2[50:70]]) # 135* 4 里面np.r 是元组 转置后是矩阵
    test = (np.r_[f_train2[20:25], f_train2[45:50], f_train2[70:75]])  # 测试样本 15*4
    # 每类的前五个样本作为训练集
    T_train = (np.r_[f_train1[0:5,], f_train1[25:30], f_train1[50:55]])
    # 训练样本中剩下的作为考试集
    T_test = (np.r_[f_train1[5:25,], f_train2[0:20], f_train1[30:50], f_train2[25:45], f_train1[55:75], f_train2[50:70]]) # 135* 4 里面np.r 是元组 转置后是矩阵

    # print(test[0, :])
    a = clip(T_train, T_test, test)
    print(a.score(test[:, 1:4], test[:, 0]))

4.压缩近邻法

原理:利用现有样本集,逐渐生成一个新的样本集。使该样本集在保留最少量样本的条件下, 仍能对原有样本的全部用最近邻法正确分类,那末该样本集也就能对待识别样本进行分类, 并保持正常识别率。它定义两个存储器,一个用来存放即将生成的样本集,称为Store;另一存储器则存放原样本集,称为Grabbag。

步骤:

  1. 初始化: Store是空集,原样本集存入Grabbag;从Grabbag中任意选择一样本放入Store中作为新样本集第一个样本。
  2. 样本集生成:在Grabbag中取出第i个样本用Store中的当前样本集按最近邻法分类。若分类错误,则将该样本从Grabbag转入Store中,若分类正确,则将该样本放回Grabbag中,对Grabbag中所有样本重复上述过程。
  3. 若Grabbag中所有样本在执行第二步时没有发生转入Store的现象,或Grabbag已成空集,则算法终止,否则转入第二步。

实验代码

import numpy as np
from MNN import MNN

def compress(X,y,test): # 135*3
    GrabbagX = X
    Grabbagy = y
    StoreX = []
    Storey = []

    StoreX.append(GrabbagX[0])
    Storey.append(Grabbagy[0])
    # print(Grabbagy.shape[0])
    cnt = 0
    while True and cnt < 100:
        cnt += 1
        flag = 0
        for i in range(len(Grabbagy)):
            # print(i+1)
            clf = MNN(StoreX, Storey)
            # print(clf.X_train)
            label = clf.predict(GrabbagX[i])
            if Grabbagy.shape[0] == 0:
                break
            if label != Grabbagy[i]:
                flag = 1
                print('第{}次'.format(cnt),'predict lable:',label,'true lable',Grabbagy[i])
                StoreX.append(GrabbagX[i])
                Storey.append(Grabbagy[i])
                list(GrabbagX).pop(i)
                list(Grabbagy).pop(i)
        if flag == 0:
            break
    # print(Storey)
    # Storey改一下  0.5333333333333333
    # Storey = [0.0, 1.0, 2.0, 2.0, 3.0, 3.0, 3.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 2.0]
    clf = MNN(StoreX,Storey)
    print('压缩近邻法正确率',clf.score(test[:, 1:4], test[:, 0]))


if __name__=="__main__":
    f_train1 = np.loadtxt("..\\iris训练数据.txt", dtype=np.double, delimiter='\t', usecols=[0, 1, 2, 3])  # 使用第123个特征
    f_train2 = np.loadtxt("..\\iris测试数据.txt", dtype=np.double, delimiter='\t', usecols=[0, 1, 2, 3])
    train = (np.r_[f_train1[0:25,], f_train2[0:20], f_train1[25:50], f_train2[25:45], f_train1[50:75], f_train2[50:70]]) # 135* 4 里面np.r 是元组 转置后是矩阵
    test = (np.r_[f_train2[20:25], f_train2[45:50], f_train2[70:75]])  # 测试样本 15*4
    compress(train[:,1:4],train[:,0],test)


你可能感兴趣的:(模式识别,python,人工智能)