如何在numpy中有效地计算高斯核[关闭]


12

我有一个具有m列和n行的numpy数组,这些列是维和行数据点。

现在,我需要为每个数据点组合计算内核值。

对于线性核我可以简单地做K(xi,xj)=xi,xjdot(X,X.T)

如何有效地计算高斯核K(xi,xj)=expxixj22s2与给定s


1
好吧,如果您不太在乎计算量会增加两个因子,则始终可以执行S=XXT,然后执行K(xi,xj)=exp((Sii+Sjj2Sij)/s2)当然,Sij(i,j)\ m S的(i,j)第th个元素。不过,这在数值上也可能不是最稳定的。S
主教

2
(几年后)有关大型稀疏数组的信息,请参见scikit-learn中的sklearn.metrics.pairwise.pairwise_distances.html
denis 2015年

Answers:


26

我认为主要问题是要有效地获取两两之间的距离。一旦有了,剩下的就是元素明智的选择。

为此,您可能要使用scipy。该功能scipy.spatial.distance.pdist可以满足您的需求,并scipy.spatial.distance.squareform可能减轻您的生活。

因此,如果您想要内核矩阵,就可以

from scipy.spatial.distance import pdist, squareform
  # this is an NxD matrix, where N is number of items and D its dimensionalites
X = loaddata() 
pairwise_dists = squareform(pdist(X, 'euclidean'))
K = scip.exp(-pairwise_dists ** 2 / s ** 2)

文档可以在这里找到。 


3
在我看来,Bayerj的答案需要一些小的修改才能适合该公式,以防其他人需要它:K = scipy.exp(-pairwise_dists**2 / s**2)
chloe 2014年

如果有人好奇,则使用的算法pdist非常简单:它只是一个C实现的循环,它以明显的方式直接计算距离,循环在这里完成;没有花哨的矢量化功能,也没有任何编译器可以自动完成的功能。
2015年

11

作为Bayerj答案的一个小附录,scipy的pdist函数可以通过将其称为来直接计算平方的欧几里德范数pdist(X, 'sqeuclidean')。然后,完整的代码可以更高效地编写为

from scipy.spatial.distance import pdist, squareform
  # this is an NxD matrix, where N is number of items and D its dimensionalites
X = loaddata() 
pairwise_sq_dists = squareform(pdist(X, 'sqeuclidean'))
K = scip.exp(-pairwise_sq_dists / s**2)

1
或者简单地pairwise_sq_dists = cdist(X, X, 'sqeuclidean')给出相同的结果。
user1721713

5

您也可以手工书写方形:

import numpy as np
def vectorized_RBF_kernel(X, sigma):
    # % This is equivalent to computing the kernel on every pair of examples
    X2 = np.sum(np.multiply(X, X), 1) # sum colums of the matrix
    K0 = X2 + X2.T - 2 * X * X.T
    K = np.power(np.exp(-1.0 / sigma**2), K0)
    return K

PS,但是速度慢30%


这是枢机主教在评论中建议的方法,可以通过使用就地操作来加快速度。它是如何scikit学习做它,有一个einsum呼叫X2
2015年

4
def my_kernel(X,Y):
    K = np.zeros((X.shape[0],Y.shape[0]))
    for i,x in enumerate(X):
        for j,y in enumerate(Y):
            K[i,j] = np.exp(-1*np.linalg.norm(x-y)**2)
    return K

clf=SVR(kernel=my_kernel)

等于

clf=SVR(kernel="rbf",gamma=1)

您可以根据上面的代码有效地计算RBF,请注意,gamma值为1,因为它是一个常数,所以您请求的s也是相同的常数。


欢迎来到我们的网站!我们对Stack Overflow的重视程度略有不同,因为我们通常较少关注代码,而更多地关注基础思想,因此可能值得注释您的代码或简要说明其关键思想,例如其他答案已经完成。这将有助于解释您的答案与其他答案有何不同。
银鱼

这将比其他答案慢很多,因为它使用Python循环而不是矢量化。
2015年

-1

我认为这会有所帮助:

def GaussianKernel(v1, v2, sigma):
    return exp(-norm(v1-v2, 2)**2/(2.*sigma**2))

3
欢迎来到@Kernel网站。您可以通过将表达式放在$符号之间并使用类似LateX的语法来显示数学。您可以通过将行缩进4个空格来显示代码(带有语法突出显示)。有关格式指南,请参见降价编辑帮助,有关常规指南,请参见常见问题解答
Antoine Vernet 2013年

1
这不只是回响问题中的内容吗?
whuber
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.