python矩阵的平方_NumPy之计算两个矩阵的成对平方欧氏距离
問題描述
設(shè)
(; 表示縱向連接) 和
, 計(jì)算矩陣
中每一個(gè)行向量和矩陣
中每一個(gè)行向量的平方歐氏距離 (pairwise squared Euclidean distance), 即計(jì)算:
(這是一個(gè)
矩陣).
這個(gè)計(jì)算在度量學(xué)習(xí), 圖像檢索, 行人重識別等算法的性能評估中有著廣泛的應(yīng)用.
公式轉(zhuǎn)化
在 NumPy 中直接利用上述原式來計(jì)算兩個(gè)矩陣的成對平方歐氏距離, 要顯式地使用二重循環(huán), 而在 Python 中循環(huán)的效率是相當(dāng)?shù)拖碌? 如果想提高計(jì)算效率, 最好是利用 NumPy 的特性將原式轉(zhuǎn)化為數(shù)組/矩陣運(yùn)算. 下面就嘗試進(jìn)行這種轉(zhuǎn)化.
先將原式展開為:
下面逐項(xiàng)地化簡或轉(zhuǎn)化為數(shù)組/矩陣運(yùn)算的形式:
式中,
表示按元素積 (element-wise product), 又稱為 Hadamard 積;
表示維的全1向量 (all-ones vector), 余者類推. 上式中
的作用是計(jì)算
每行元素的和, 返回一個(gè)列向量;
的作用類似于 NumPy 中的廣播機(jī)制, 在這里是將一個(gè)列向量擴(kuò)展為一個(gè)矩陣, 矩陣的每一列都是相同的.
所以:
上述轉(zhuǎn)化式中出現(xiàn)了
(矩陣乘) , 矩陣乘在 NumPy 等很多庫中都有高效的實(shí)現(xiàn), 對代碼的優(yōu)化是有好處的.
特別地, 當(dāng)
時(shí), 原式等于
, 注意到第一項(xiàng)和第二項(xiàng)互為轉(zhuǎn)置. 當(dāng)
且
(即
和
的每一個(gè)行向量的范數(shù)均為1時(shí)), 原式等于
,
是
全1矩陣.
代碼實(shí)現(xiàn)
sklearn 中已經(jīng)包含了用 NumPy 實(shí)現(xiàn)的計(jì)算 "兩個(gè)矩陣的成對平方歐氏距離" 的函數(shù) (sklearn.metrics.euclidean_distances
import numpy as np
def euclidean_distances(x, y, squared=True):
"""Compute pairwise (squared) Euclidean distances."""
assert isinstance(x, np.ndarray) and x.ndim == 2
assert isinstance(y, np.ndarray) and y.ndim == 2
assert x.shape[1] == y.shape[1]
x_square = np.sum(x*x, axis=1, keepdims=True)
if x is y:
y_square = x_square.T
else:
y_square = np.sum(y*y, axis=1, keepdims=True).T
distances = np.dot(x, y.T)
# use inplace operation to accelerate
distances *= -2
distances += x_square
distances += y_square
# result maybe less than 0 due to floating point rounding errors.
np.maximum(distances, 0, distances)
if x is y:
# Ensure that distances between vectors and themselves are set to 0.0.
# This may not be the case due to floating point rounding errors.
distances.flat[::distances.shape[0] + 1] = 0.0
if not squared:
np.sqrt(distances, distances)
return distances
如果想進(jìn)一步加速, 可以將
x_square = np.sum(x*x, axis=1, keepdims=True)
替換為
x_square = np.expand_dims(np.einsum('ij,ij->i', x, x), axis=1)
以及將
y_square = np.sum(y*y, axis=1, keepdims=True).T
替換為
y_square = np.expand_dims(np.einsum('ij,ij->i', y, y), axis=0)
使用 np.einsum 的好處是不會產(chǎn)生一個(gè)和 x 或 y 同樣形狀的臨時(shí)數(shù)組 (x*x 或 y*y 會產(chǎn)生一個(gè)和 x 或 y 同樣形狀的臨時(shí)數(shù)組).
PyTorch 中也包含了計(jì)算 "兩個(gè)矩陣的成對平方歐氏距離" 的函數(shù)
另外上述的轉(zhuǎn)化公式也可以用在其他 Python 框架 (如 TensorFlow) 或其他語言中, 這里就不展開敘述了.
版權(quán)聲明
版權(quán)聲明:自由分享,保持署名-非商業(yè)用途-非衍生,知識共享3.0協(xié)議。
如果你對本文有疑問或建議,歡迎留言!轉(zhuǎn)載請保留版權(quán)聲明!
參考
總結(jié)
以上是生活随笔為你收集整理的python矩阵的平方_NumPy之计算两个矩阵的成对平方欧氏距离的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python权限不够无法写入_解决pyt
- 下一篇: python就是玩具_极客老爹的玩具DI