简要介绍KNN(K Nearest Neighbor)
Nearest Neighbor
介绍KNN以前,我们先了解一下Nearest Neighbor。Nearest Neighbor主要用于分类,以CIFAR-10数据集为例,有50000张训练图片和与之对应的标签。我们将要为测试集标上标签,我们取一张测试集中的图片,在训练集中找出与之最相似的一张图片,那么该测试集图片与该最相似的一张的图片的标签相同。但是这样也有局限性。
以改图为例,我们现在要对绿色圆形进行分类,看起来绿色圆形仿佛应该属于红色三角形,但是事实可能往往并不是这样,所以便有了KNN。
K Nearest Neighbor
如果一个样本在特征空间中的K个最相邻的样本中的大多数属于某一个类别,则该样本也属于这个类别,并具有这个类别上样本的特性。该方法在确定分类决策上只依据最邻近的一个或者几个样本的类别来决定待分样本所属的类别。 KNN方法在类别决策时,只与极少量的相邻样本有关。由于KNN方法主要靠周围有限的邻近的样本,而不是靠判别类域的方法来确定所属类别的,因此对于类域的交叉或重叠较多的待分样本集来说,KNN方法较其他方法更为适合。
KNN算法比NN算法误差要小一些,因为KNN中的K我们可以通过在训练集找到一个比较好的K,在测试集上KNN的误差比NN的误差要小。
还是以此图为例,如果用NN算法,绿色圆形本应属于红色三角形,当K=3时,也是如此。但是当K=5时,绿色圆形属于蓝色三角性,可见,绿色圆点到底属于哪一类,与具体的K有关。所以我们要看分类的对象,并训练KNN分类器,毕竟如果NN算法要好的话,也是KNN算法中K=1的特殊情况。
也就是说:K Nearest Neighbor 算法包含了 Nearest Neighbor算法
如何度量相似
L1(Manhattan)distance
L2 distance
numpy技巧
idxs = np.flatnonzero(): 返回非0元素的位置
idxs = np.random.choice():从数组中随机抽取元素
plt.subplot():子图绘制
np.linalg.norm():计算范数
np.array_split():数组划分
np.vstack(): 按垂直方向(行顺序)堆叠数组构成一个新的数组
np.hstack(): 按水平方向(列顺序)堆叠数组构成一个新的数组
np.argsort():排序,返回索引值
np.bincount():返回每个索引出现的次数
KNN代码实现
github:https://github.com/GIGpanda/CS231n
一共两个.py文件,knn.py和k_nearest_neighbor.py
knn.py
数据加载
加载CIFAR-10数据,并打印训练集和测试集的图片、标签尺寸。
# KNN
from __future__ import print_function
import random
import numpy as np
from cs231n.data_utils import load_CIFAR10
import matplotlib.pyplot as plt
from cs231n.classifiers import KNearestNeighbor
import time
plt.rcParams['figure.figsize'] = (10.0, 8.0) # set default size of plots
plt.rcParams['image.interpolation'] = 'nearest'
plt.rcParams['image.cmap'] = 'gray'
# Load the raw CIFAR-10 data.
cifar10_dir = 'cs231n/datasets/cifar-10-batches-py'
X_train, y_train, X_test, y_test = load_CIFAR10(cifar10_dir)
# As a sanity check, we print out the size of the training and test data.
print('Training data shape: ', X_train.shape)
print('Training labels shape: ', y_train.shape)
print('Test data shape: ', X_test.shape)
print('Test labels shape: ', y_test.shape)
可视化部分数据
对于训练集中的10类数据,每类随机取出7张并可视化。
# Visualize some examples from the dataset.
# We show a few examples of training images from each class.
classes = ['plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck']
num_classes = len(classes)
samples_per_class = 7
for y, cls in enumerate(classes):
idxs = np.flatnonzero(y_train == y) # np.flatnonzero 返回非0元素的位置
idxs = np.random.choice(idxs, samples_per_class, replace=False)
# np.random.choice 从数组中随机抽取元素
# 从数组idxs中随机抽取数字, 组成大小为samples_per_class的数组, replace=False表示不可以取相同的数字
for i, idx in enumerate(idxs):
plt_idx = i * num_classes + y + 1
# plt_idx 算出每张图片打印出来的位置 也就是同一类图片在同一列
plt.subplot(samples_per_class, num_classes, plt_idx)