Как эффективно вычислить ядро ​​Гаусса в numpy [закрыто]


12

У меня есть пустой массив с m столбцами и n строками, столбцы с размерами и точками данных строк.

Теперь мне нужно рассчитать значения ядра для каждой комбинации точек данных.

Для линейного ядра я могу просто сделатьK(xi,xj)=xi,xjdot(X,X.T)

Как эффективно рассчитать все значения для гауссова ядра с заданным s ?K(xi,xj)=expxixj22s2


1
Ну, если вас не слишком заботит увеличение коэффициента в два раза, вы всегда можете просто сделать и затем где, конечно, - это й элемент . Это, вероятно, не самая численно стабильная, хотя, однако. S=XXTK(xi,xj)=exp((Sii+Sjj2Sij)/s2)Sij(i,j)S
кардинал

2
(Годы спустя) для больших разреженных массивов см. Sklearn.metrics.pairwise.pairwise_distances.html в scikit-learn.
Денис

Ответы:


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)
Хлоя

Если кому-то любопытно, используемый алгоритм pdistочень прост: это просто C-реализованный цикл, который напрямую вычисляет расстояния очевидным образом , цикл выполняется здесь ; никакая причудливая векторизация или что-то помимо того, что компилятор может выполнить автоматически.
Дугал

11

В качестве небольшого дополнения к ответу Байержа, 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.
Дугал

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, поскольку оно является константой, которую вы запрашивали, также является той же константой.


Добро пожаловать на наш сайт! У нас немного другой акцент на переполнение стека, так как мы, как правило, уделяем меньше внимания коду и уделяем больше внимания базовым идеям, поэтому, возможно, стоит аннотировать ваш код или дать краткое представление о том, каковы его ключевые идеи, как некоторые из другие ответы сделали. Это поможет объяснить, как ваш ответ отличается от других.
Серебряная

Это будет намного медленнее, чем другие ответы, потому что он использует петли Python, а не векторизацию.
Дугал

-1

Я думаю, что это поможет:

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

3
Добро пожаловать на сайт @Kernel. Вы можете отобразить математику, поместив выражение между знаками $ и используя синтаксис LateX. И вы можете отобразить код (с подсветкой синтаксиса), сделав отступы на 4 пробела. См уценки редактирования справки для форматирования руководящих принципов, а также Справка для более общих.
Антуан Вернет

1
Разве это не просто отражает то, что в вопросе?
whuber
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.