跳转至

l2 距离无循环计算方法

[toc]

描述

对于一个向量 X[x0, x1, ... xn] 和向量 Y[y0, y1, ... yn]。其 L2 距离表示为

\[ d = \sqrt{\sum_{i=0}(xi - yi)^2} \]

一维向量 x 一维向量

两个一维向量计算 l2 距离

x,y

x.shape
(4, )
y.shape
(4,)

d = np.sqrt(np.sum(np.square(x-y)))

逐步解释

  • x-y: 逐元素相减,大小为 (4, )
  • np.square: 逐元素平方,操作结果为(4, )
  • np.sum: 聚合操作,所有元素求和,操作结果为 一个值
  • np.sqrt:逐元素操作,对元素进行开方,结果为一个值

如果两个向量,一个一维向量和一个多维向量,进行 l2 据

一维向量 x 多维度向量

一个一维向量和一个多维向量计算 l2 距离

假设x(n, ) y (2, n) ,需要将 x 分别和 y 中的每一行做 l2 距离计算,所得的结果应该是 (2, )

为了将 x 和 y 每一行都做 l2 距离计算,需要将 x 进行复制, x(n, ) -> x(2, n)\ 这样只需要将 x - y 得到的每一行都是 x 与 yi 操作的结果,然后统一别对每行进行聚合运算即可,在扩展 x 之后,后续的操作和一维向量相同。

x.shape
(4, )
y.shape
(2, 4)

d = np.sqrt(np.sum(np.square(x-y), axis=1))
  • axis=1: 对聚合操作来说,axis 为多少,表示在该维度上进行运算,压缩该维度

多维向量 x 多维向量

多维向量与多维向量的 l2 距离结果应该是一个二维矩阵 d[x,y]。 d[xi,yi] 表示 x 中的第 i 行与 y 中第 i 行的距离

方法一

假设 x[m, p], y[n, p],可以进行升维度,变为 x[m,n,p], y[m,n,p],维度相同之后,就可以进行逐元素减法,x - y,然后沿着最后一个维度聚合,得到 d[m, n]

x = x.reshape(x.shape[0], 1, x.shape[1])
y = y.reshape(1, y.shape[0], y.shape[1])

d = np.sqrt(np.sum(np.square(x-y), axis=2))

方法二

根据计算公式 $$ d = \sqrt{\sum_{i=0}^n(x_i - y_i)^2} $$

\[ d = \sqrt{\sum_{i=0}^nx_i^2 + \sum_{i=0}^ny_i^2 - 2\sum_{i=0}^{n}x_iy_i} \]

即对于2个多维矩阵x[m,p] y[n,p],可以分三个部分分别计算,首先分别计算这两个矩阵的平方和

x_square_sum = np.sum(np.square(x), axis=1)
y_square_sum = np.sum(np.square(y), axis=1)

x_square_sum.shape
(m, )

y_square_sum.shape
(n, )

然后将这两个矩阵进行升维,后求和计算

x_square_sum = x_square_sum[:, np.newaxis]
(m, 1)
y_square_sum = y_square_sum[np.newaxis, :]
(1, n)
x_y_square_sum = x_square_sum + y_square_sum
(m,n)

其中 x_y_square_sum[i,j] 表示 x 的第 i 个向量与 y 的第 j 个向量的平方加和

式子的第二部分,恰好与矩阵乘法一致

x_y_dot = np.dot(x, y.T)

x_y_dot.shape
(m, n)

此时就得到了两个大小均为 (m,n) 的矩阵,将两个式子组合,最终的距离向量矩阵计算为

x_square_sum = np.sum(np.square(x), axis=1)
y_square_sum = np.sum(np.square(y), axis=1)
x_y_square_sum = x_square_sum.reshap[:, np.newaxis] + 
y_square_sum[np.newaxis, 1]

x_y_dot = np.dot(x, y.T)

d = np.sqrt(x_y_square_sum - 2*x_y_dot)

参考链接