KNN介绍

简介
  • k近邻法(k-nearest neighbors)是由Cover和Hart于1968年提出的,它是懒惰学习(lazy learning)的著名代表。
  • k近邻算法是一种基本分类和回归方法。本篇作为学习笔记,暂时只讨论分类问题的k近邻法。
  • 距离衡量的标准有很多,常见的有:Lp距离、切比雪夫距离、马氏距离、巴氏距离、余弦值等。
算法步骤概述
  1. 给定一个测试样本
  2. 计算测试样本中每个点到训练样本中每个点的距离
  3. 取离测试样本最近的k个训练样本
  4. 选出在这k个样本中出现最多的类别,就是预测的结果

PYTHON对矩阵进行最短距离法聚类 python计算距离矩阵_算法


根据上面的流程简要做个概述:

  1. 中心点的绿色为测试样本,一共有两种类型,分为红色的三角形和蓝色的正方形
  2. 计算绿色到其他点的距离
  3. 选取距离测试样本最近的K个点。当K=3时,红色三角形数量多,分类结果为红色三角形。当K=5时,蓝色正方形数量多,分类结果为蓝色正方形。
欧式距离计算概述
双重循环
import numpy as np
def cal_l2_distance_two_loops(test_X, train_X):
    """
    计算L2距离,两层循环
    :return:
    """
    num_test = test_X.shape[0]
    num_train = train_X.shape[0]
    dists = np.zeros((num_test, num_train))
    for i in range(num_test):
        for j in range(num_train):
            test_line = test_X[i]
            train_line = train_X[j]
            temp = np.subtract(test_line, train_line)
            temp = np.power(temp, 2)
            dists[i][j] = np.sqrt(temp.sum())
    return dists
一层循环
import numpy as np
def cal_l2_distances_one_loop(test_X, train_X):
    """
    计算L2距离,一层循环
    :return:
    """
    num_test = test_X.shape[0]
    num_train = train_X.shape[0]
    dists = np.zeros((num_test, num_train))
    for i in range(num_test):
        dists[i] = np.sqrt(np.sum(np.square(train_X - test_X[i]), axis=1)).T
    return dists
通过矩阵计算

运算效率最高的算法是将训练集和测试集都使用矩阵表示,然后使用矩阵运算的方法替代之前的循环操作。但此操作需要我们对矩阵的运算规则非常熟悉。接下来着重记录如何计算两个矩阵之间的欧式距离。

记录测试集矩阵P的大小为MD,训练集矩阵C的大小为ND(测试集中共有M个点,每个点为D维特征向量。训练集中共有N个点,每个点为D维特征向量)

PYTHON对矩阵进行最短距离法聚类 python计算距离矩阵_机器学习_02是P的第i行,记PYTHON对矩阵进行最短距离法聚类 python计算距离矩阵_机器学习_02是C的第j行
PYTHON对矩阵进行最短距离法聚类 python计算距离矩阵_机器学习_04 PYTHON对矩阵进行最短距离法聚类 python计算距离矩阵_k近邻_05

首先计算PYTHON对矩阵进行最短距离法聚类 python计算距离矩阵_机器学习_02PYTHON对矩阵进行最短距离法聚类 python计算距离矩阵_k近邻_07之间的距离dist(i,j)
PYTHON对矩阵进行最短距离法聚类 python计算距离矩阵_k近邻_08

我们可以推广到距离矩阵的第i行的计算公式
PYTHON对矩阵进行最短距离法聚类 python计算距离矩阵_机器学习_09
注意:这里公式中的第二项为什么是PYTHON对矩阵进行最短距离法聚类 python计算距离矩阵_PYTHON对矩阵进行最短距离法聚类_10呢,因为算的是i行的距离。即测试样本的第i行到训练样本中每一个点的距离。如果对这个不是很清楚的同学,可以看看下面参看文章中的第三个链接。

继续将公式推广为整个距离矩阵
PYTHON对矩阵进行最短距离法聚类 python计算距离矩阵_PYTHON对矩阵进行最短距离法聚类_11
通过矩阵计算两个之前的欧式距离的代码,参看博客中的代码好像都有问题,下面是我根据下面的公式,自己写的一个。

import numpy as np
def cal_l2_distances_no_loops(test_X, train_X):
	"""
	计算L2距离,通过矩阵运算
	:return:
	"""
	
	first = np.sum(np.square(test_X), axis=1)
	second = np.sum(np.square(train_X), axis=1).T
	# 注意这里的np.dot(test_X, train_X.T)中的test_X, train_X位置是和公式中的顺序保持一致的
	three = -2 * np.dot(test_X, train_X.T)
	
	dists = np.sqrt(first + second + three)
	return dists
代码合在一起
import numpy as np


class MatrixDistance(object):
    """计算两个矩阵之的L2距离(欧式距离)"""

    def __init__(self, train_X, test_X):
        self.train_X = train_X
        self.test_X = test_X

    def cal_l2_distance_two_loops(self):
        """
        计算L2距离,两层循环
        :return:
        """
        num_test = self.test_X.shape[0]
        num_train = self.train_X.shape[0]
        dists = np.zeros((num_test, num_train))
        for i in range(num_test):
            for j in range(num_train):
                test_line = self.test_X[i]
                train_line = self.train_X[j]
                temp = np.subtract(test_line, train_line)
                temp = np.power(temp, 2)
                dists[i][j] = np.sqrt(temp.sum())
        return dists

    def cal_l2_distances_one_loop(self):
        """
        计算L2距离,一层循环
        :return:
        """
        num_test = self.test_X.shape[0]
        num_train = self.train_X.shape[0]
        dists = np.zeros((num_test, num_train))
        for i in range(num_test):
            dists[i] = np.sqrt(np.sum(np.square(self.train_X - self.test_X[i]), axis=1)).T
        return dists

    def cal_l2_distances_no_loops(self):
        """
        计算L2距离,通过矩阵运算
        :return:
        """

        first = np.sum(np.square(self.test_X), axis=1)
        second = np.sum(np.square(self.train_X), axis=1).T
        # 注意这里的np.dot(self.test_X, self.train_X.T)中的test_X, train_X位置是和前面的顺序保持一致的
        three = -2 * np.dot(self.test_X, self.train_X.T)

        dists = np.sqrt(first + second + three)
        return dists


if __name__ == '__main__':
    train_x = np.matrix(np.arange(12).reshape(3, 4))
    test_x = np.matrix(np.arange(2, 14).reshape(3, 4))

    d = MatrixDistance(train_x, test_x)
    print(d.cal_l2_distance_two_loops())
    print(d.cal_l2_distances_one_loop())
    print(d.cal_l2_distances_no_loops())

参考文章:
计算两个矩阵之间的欧式距离k近邻算法K-近邻算法介绍与代码实现