2.1 基本思路
- 给定一张测试图片,计算它与训练集中所有图片的距离(即相似度,距离越小相似度越高)
- 找出与测试图片距离最小一张训练集图片
- 将该训练集图片的类别作为测试图片的类别
2.2 图片距离的定义(相似性度量)
采用L1距离:
其中, 是两张图片,
是图片中的像素。
def l1(img1, img2):
""" 计算图片间的L1距离
Args:
img1 (np.ndarray): 二维数组(图片像素为28×28)
img2 (np.ndarray): 二维数组
Returns:
float: 图片L1距离
"""
return np.sum(abs(img1 - img2))
2.3 实现最近邻算法
2.3.1 定义模型
模型没有参数,只保存训练集的图片和标签。
class NearestNeighbor(object):
def __init__(self):
""" 最近邻模型 """
self.train_images = []
self.train_labels = []
2.3.3 训练模型
训练过程就是保存训练集数据的过程。
def train(train_images, train_labels):
""" 训练模型
Args:
train_images (list[np.ndarray]): 图片集
train_labels (list[int]): 标签集
Returns:
NearestNeighbor: 训练好的模型
"""
model = NearestNeighbor()
model.train_images = train_images
model.train_labels = train_labels
return model
2.3.4 预测
预测时,将测试图片与训练集图片一一对比,找出最相似(L1距离最小)的一张,返回其类别。
def predict(model, test_image):
""" 预测图片类别
Args:
model (NearestNeighbor): 训练好的模型
test_image (np.ndarray): 测试图片,28×28矩阵
Returns:
int: 预测的类别(0~9)
"""
all_l1 = [l1(test_image, image) for image in model.train_images]
similar_image_index = np.argmin((all_l1)
label = model.train_labels[similar_image_index]
return label
2.3.5 评估预测准确率
- 定义自己的混淆矩阵类:
from sklearn.metrics import confusion_matrix
class ConfMat(object):
"""Confusion matrix
Args:
true_y (np.ndarray or list[int]): 真实标签值
pred_y (np.ndarray or list[int]): 预测标签值
"""
def __init__(self, y, pred):
assert len(true_y) == len(pred_y)
confmat = confusion_matrix(true_y, pred_y).transpose().astype(int)
self.n_classes = confmat.shape[0]
self.confmat = np.zeros((self.n_classes + 1, self.n_classes + 1))
self.confmat[:-1, :-1] = confmat
self.accuracy = self.confmat.diagonal().sum() / self.confmat.sum()
self.precisions = np.zeros(self.n_classes)
self.recalls = np.zeros(self.n_classes)
for i in range(self.n_classes):
row_sum = self.confmat[i, :].sum()
self.precisions[i] = self.confmat[i, i] / row_sum if row_sum > 0 else 0
col_sum = self.confmat[:, i].sum()
self.recalls[i] = self.confmat[i, i] / col_sum if col_sum > 0 else 0
self.confmat[-1, :-1] = self.recalls
self.confmat[:-1, -1] = self.precisions
self.confmat[-1, -1] = self.accuracy
- 在测试集上评估模型,并计算混淆矩阵:
def get_confmat(model, test_images, test_labels):
""" 用测试集评估模型,得到混淆矩阵
Args:
model (NearestNeighbor): 训练好的模型
test_images (list[np.ndarray]): 测试集图片
test_labels (list[int]): 测试集标签
Returns:
np.array: 混淆矩阵
"""
pred_labels = [predict(model, image) for image in test_images]
return ConfMat(test_labels, pred_labels)
- 评估结果:
准确率
973, 0, 9, 0, 1, 2, 5, 0, 9, 1, 0.973
2, 1129, 8, 2, 9, 1, 2, 20, 5, 5, 0.954
1, 3, 987, 4, 0, 0, 1, 4, 6, 1, 0.980
0, 0, 6, 965, 0, 17, 0, 2, 21, 7, 0.948
0, 1, 1, 1, 937, 2, 2, 4, 4, 13, 0.971
1, 1, 0, 21, 0, 848, 5, 0, 18, 5, 0.943
2, 1, 2, 0, 3, 9, 943, 0, 3, 1, 0.978
1, 0, 17, 9, 4, 1, 0, 989, 4, 9, 0.956
0, 0, 2, 4, 1, 5, 0, 0, 894, 1, 0.986
0, 0, 0, 4, 27, 7, 0, 9, 10, 966, 0.944
召回率:0.993, 0.995, 0.956, 0.955, 0.954, 0.951, 0.984, 0.962, 0.918, 0.957, 0.963
网友评论