代码之家  ›  专栏  ›  技术社区  ›  Yu Chen little_birdie

多维特征径向基函数欧氏距离的矢量化计算

  •  0
  • Yu Chen little_birdie  · 技术社区  · 6 年前

    我怀疑可能有这么一个帖子回答了这个问题,但我还没有找到,所以如果这是一个重复的问题,我提前道歉。

    我正试图从头开始实现一个径向基函数内核,使用numpy实现我自己的学习目的。对于一维输入,计算非常简单:

    def kernel(x, y):
        return * np.exp( -0.5 * np.subtract.outer(x, y)**2)
    

    以上内容来自 blog post on Gaussian Processes .

    但我想把它扩展到多个维度。我有一个在下面运行良好的实现:

    x = np.array([[4,3,5], [1,3,9], [0,1,0], [4,3,5]])
    distances = []
    γ = -.5
    for i in x:
        for j in x:
            distances.append(np.exp(γ * np.linalg.norm(i - j) ** 2))
    np.array(distances).reshape(len(x),len(x))
    
    [[1.00000000e+00 3.72665317e-06 1.69189792e-10 1.00000000e+00]
     [3.72665317e-06 1.00000000e+00 2.11513104e-19 3.72665317e-06]
     [1.69189792e-10 2.11513104e-19 1.00000000e+00 1.69189792e-10]
     [1.00000000e+00 3.72665317e-06 1.69189792e-10 1.00000000e+00]]
    

    我正在检查使用 sklearn.pairwise.rbf_kernel

    from sklearn.metrics.pairwise import rbf_kernel
    print(rbf_kernel(x, gamma= .5))
    
    [[1.00000000e+00 3.72665317e-06 1.69189792e-10 1.00000000e+00]
     [3.72665317e-06 1.00000000e+00 2.11513104e-19 3.72665317e-06]
     [1.69189792e-10 2.11513104e-19 1.00000000e+00 1.69189792e-10]
     [1.00000000e+00 3.72665317e-06 1.69189792e-10 1.00000000e+00]]
    

    但显然,double for循环并不是最有效的迭代方法。什么是使这个操作向量化的最佳方法?

    这个 SO post 提供了计算距离的有效方法,但不提供我需要的矢量化。

    2 回复  |  直到 6 年前
        1
  •  1
  •   Abhishek Mishra    6 年前

    您可以使用以下观察来解决问题:

    ||a - b|| ** 2 = ||a|| ** 2 + ||b|| ** 2 - 2 * <a, b>

    在代码中,它看起来如下:

    x_norm = np.linalg.norm(x, axis=1) ** 2
    output = np.exp(- 0.5 * (x_norm.reshape(-1, 1) + x_norm.reshape(1, -1) - 2 * np.dot(x, x.T)))
    
        2
  •  1
  •   Divakar    6 年前

    我们可以用 SciPy's cdist 然后用指数值缩放-

    from scipy.spatial.distance import cdist
    
    lam = -.5
    out = np.exp(lam* cdist(x,x,'sqeuclidean'))
    

    我们也可以 leverage matrix-mutliplication -

    def sqcdist_own(x):
        row_sum = (x**2).sum(1) # or np.einsum('ij,ij->i',x,x)
        sqeucdist = row_sum - 2*x.dot(x.T)
        sqeucdist += row_sum[:,None]
        return sqeucdist
    
    out = np.exp(lam* cdist(x,x,'sqeuclidean'))
    

    使用这些方法 2D 1D 病例,整形 x 二维 作为预处理步骤: X = x.reshape(len(x),-1) 然后使用 X 而是作为这些解决方案的输入。