计算矩阵的欧式距离

对于kNN算法,难点在于计算测试集中每一样本到训练集中每一样本的欧氏距离,即计算两个矩阵之间的欧氏距离。现就计算欧式距离提出三种方法。

1. 两层循环

分别对训练集和测试集中的数据进行循环遍历,计算每两个样本之间的欧式距离。此算法没有经过任何优化。

import numpy as np
matrix_1 = np.array([[1, 2, 3],
            [4, 5, 6],
            [7, 8, 9]])
matrix_2 = np.array([[1, 2, 3],
            [4, 5, 6],
            [7, 8, 9],
            [3, 2, 1],
            [6, 5, 4],
            [9, 8, 7]])
def compute_distances_two_loop(test_matrix, train_matrix):
    num_test = test_matrix.shape[0]
    num_train = train_matrix.shape[0]
    dists = np.zeros((num_test, num_train))    # shape(num_test, num-train)   
    for i in range(num_test):
        for j in range(num_train):
            # corresponding element in Numpy Array can compute directly,such as plus, multiply
            dists[i][j] = np.sqrt(np.sum(np.square(test_matrix[i] - train_matrix[j])))  
    return dists
compute_distances_two_loop(matrix_1, matrix_2)

在这里插入图片描述

2. 一层循环

利用Numpy广播机制(参见下一篇博客)对方法一进行优化,使用一层循环。

def compute_distances_one_loop(test_matrix, train_matrix):
    num_test = test_matrix.shape[0]
    num_train = train_matrix.shape[0]
    dists = np.zeros((num_test, num_train))
    for i in range(num_test):
        dists[i] = np.sqrt(np.sum(np.square(test_matrix[i] - train_matrix), axis=1))
    return dists
compute_distances_one_loop(matrix_1, matrix_2)

在这里插入图片描述

3. 不使用循环

计算效率最高的算法是将训练集和测试集都使用矩阵表示,然后使用矩阵运算的方法替代之前的循环操作。但矩阵运算要求我们对矩阵的运算规则非常熟悉。现就计算两个矩阵之间的欧式距离的矩阵运算进行推导。
假设测试集矩阵T的大小为MD,训练集矩阵P的大小为ND(测试集中共有M个点,每个点为D维特征向量;训练集中共有N个点,每个点为D维特征向量)。
记Ti是测试集矩阵T的第i行,Pj是训练集矩阵P的第j行。

  1. 计算Ti与Pj之间的距离dists[i][j]:
    dists[i][j] = ( T   i 1   P   j 1   ) 2 + ( T   i 2   P   j 2   ) 2 + . . . . . . + ( T   i k   P   j k   ) 2 + . . . . . . + ( T   i D   P   j D   ) 2 \sqrt[]{(T~i1~-P~j1~)^2 + (T~i2~-P~j2~)^2 +......+ (T~ik~-P~jk~)^2 +......+ (T~iD~-P~jD~)^2}
    = ( T   i 1   2 + T   i 2   2 + . . . . . . + T   i D   2 ) + ( P   j 1   2 + P   j 2   2 + . . . . . . + P   j D   2 ) 2 ( T   i 1   P   j 1   + T   i 2   P   j 2   + . . . . . . + T   i D   P   j D   ) \sqrt[]{(T~i1~^2 + T~i2~^2 +......+ T~iD~^2) + (P~j1~^2 + P~j2~^2 +......+P~jD~^2) - 2 * (T~i1~P~j1~ + T~i2~P~j2~ +......+ T~iD~P~jD~)}
    = T   i   2 + P   j   2 2 T   i   P   j   \sqrt[]{||T~i~||^2 + ||P~j~||^2 - 2 * T~i~P~j~}
  2. 推广到距离矩阵的第i行的计算公式:
    dists[i] = ( T   i   2 + T   i   2 + . . . . . . + T   i   2 ) + ( P   1   2 + P   2   2 + . . . . . . + P   N   2 ) 2 T   i   ( P   1   T + P   2   T + . . . . . . + P   N   T ) \sqrt[]{(||T~i~||^2 + ||T~i~||^2 +......+ ||T~i~||^2) + (||P~1~||^2 + ||P~2~||^2 +......+ ||P~N~||^2) - 2 * T~i~(P~1~^T + P~2~^T +...... + P~N~^T)}
    = ( T   i   2 + T   i   2 + . . . . . . + T   i   2 ) + ( P   1   2 + P   2   2 + . . . . . . + P   N   2 ) 2 T   i   P T \sqrt[]{(||T~i~||^2 + ||T~i~||^2 +......+ ||T~i~||^2) + (||P~1~||^2 + ||P~2~||^2 +......+ ||P~N~||^2) - 2 * T~i~P^T}
  3. 将公式推广为整个距离矩阵 :
    dists =
    \sqrt[]{}
    { T   1   2 T   1   2 T   1   2 T   2   2 T   2   2 T   2   2 T   M   2 T   M   2 T   M   2 } \left\{ \begin{matrix} ||T~1~||^2 & ||T~1~||^2 & \cdots & ||T~1~||^2 \\ ||T~2~||^2 & ||T~2~||^2 & \cdots & ||T~2~||^2\\ \cdots & \cdots & \cdots & \cdots\\ ||T~M~||^2 & ||T~M~||^2 & \cdots & ||T~M~||^2 \end{matrix} \right\}
    +
    { P   1   2 P   2   2 P   N   2 P   1   2 P   2   2 P   N   2 P   1   2 P   2   2 P   N   2 } \left\{ \begin{matrix} ||P~1~||^2 & ||P~2~||^2 & \cdots & ||P~N~||^2 \\ ||P~1~||^2 & ||P~2~||^2 & \cdots & ||P~N~||^2\\ \cdots & \cdots & \cdots & \cdots\\ ||P~1~||^2 & ||P~2~||^2 & \cdots & ||P~N~||^2 \end{matrix} \right\}
    +
    T P T TP^T
    在这里插入图片描述
    具体实现见下:
def non_loop(test_matrix, train_matrix):
    num_test = test_matrix.shape[0]
    num_train = train_matrix.shape[0]
    dists = np.zeros((num_test, num_train))
    # because(X - X_train)*(X - X_train) = -2X*X_train + X*X + X_train*X_train, so
    d1 = -2 * np.dot(test_matrix, train_matrix.T)    # shape (num_test, num_train)
    d2 = np.sum(np.square(test_matrix), axis=1, keepdims=True)    # shape (num_test, 1)
    d3 = np.sum(np.square(train_matrix), axis=1)     # shape (1, num_train)
    dists = np.sqrt(d1 + d2 + d3)
    return dists
non_loop(matrix_1, matrix_2)

在这里插入图片描述
注:Numpy数组运算的广播机制与对应元素运算原则。

猜你喜欢

转载自blog.csdn.net/qq_33254870/article/details/82933317