numpyでガウスカーネルを効果的に計算する方法[終了]


12

私はm列とn行の派手な配列を持っています。列は次元で、行はデータポイントです。

次に、データポイントの組み合わせごとにカーネル値を計算する必要があります。

線形カーネルのための私は単純に行うことができますK(xi,xj)=xi,xjdot(X,X.T)

私は効果的にガウスカーネルのすべての値を計算することができますどのように与えられたsを持つ s 2K(xi,xj)=expxixj22s2


1
計算の2倍の増加をあまり気にしない場合は、を実行してからここで、もちろんは th番目の要素。これはおそらくありませんけれども、最も数値的に安定した、のいずれか。S=XXTK(xi,xj)=exp((Sii+Sjj2Sij)/s2)Sij(i,j)S
枢機卿

2
(数年後)大規模なスパース配列については、scikit-learnのsklearn.metrics.pairwise.pairwise_distances.htmlを参照してください。
denis

回答:


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

誰かが興味を持っている場合、で使用されるアルゴリズムpdistは非常に単純です。これは、Cで実装されたループであり、明らかな方法で距離を直接計算します。ループはここで行われます。派手なベクトル化や、コンパイラーが自動的に実行できる以上のものはありません。
Dougal 2017年

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 2018年

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学習で、コールあなたのために。einsumX2
Dougal 2017年

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を計算できます。ガンマ値は1であることに注意してください。これは定数なので、要求したsも同じ定数です。


当サイトへようこそ!スタックオーバーフローの重点は少し異なります。通常、コードに重点を置くのではなく、根底にあるアイデアに重点を置いているため、コードの注釈を付けたり、主要なアイデアを簡単に説明したりすることをお勧めします。他の答えがしました。それはあなたの答えが他の人とどのように異なるかを説明するのに役立ちます。
Silverfish 2017年

これは、ベクトル化ではなくPythonループを使用するため、他の回答よりもはるかに遅くなります。
Dougal 2017年

-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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.