目录
一、实验内容及要求
二、实验原理及代码
1.近邻法原理及其决策规则
2.k-近邻法决策规则
3.剪辑近邻法
4.压缩近邻法
1.使用IRIS数据集,每个类别选45个训练样本,5个测试样本,分别用最近邻法、k近邻法对测试样本进行分类,比较分类错误率;
2.调整k的值,比较不同的k值对错误率的影响.
3.采用剪辑近邻法和压缩近邻法对训练数据进行处理,用优化后的训练样本集对测试集进行分类,比较分类错误率
4.使用python实现
最小距离分类器:将各类训练样本划分成若干子类,并在每个子类中确定代表点。测试样本的类别则以其与这些代表点距离最近作决策。该法的缺点:所选择的代表点并不一定能很好地代表各类,其后果将使错误率增加。
以全部训练样本作为“代表点”,计算测试样本与这些“代表点”,即所有样本的距离,并以最近邻者的类别作为决策。
最近邻法决策规则:将与测试样本最近邻样本的类别作为决策的方法称为最近邻法。
对一个C类别问题,每类有Ni个样本,i=1,…,C,则第i类ωi的判别函数
判别函数的决策规则:
表示是ω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)
在所有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)
原理:从训练数据集中剔除两类交界处容易错分的样本,从而减少训练样本集,降低错误率。
步骤:
(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]))
原理:利用现有样本集,逐渐生成一个新的样本集。使该样本集在保留最少量样本的条件下, 仍能对原有样本的全部用最近邻法正确分类,那末该样本集也就能对待识别样本进行分类, 并保持正常识别率。它定义两个存储器,一个用来存放即将生成的样本集,称为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)