Як ефективно обчислити ядро ​​Гаусса в numpy [закрито]


12

У мене є nummy масив з m стовпцями та n рядками, стовпці мають розміри та рядки даних.

Тепер мені потрібно обчислити значення ядра для кожної комбінації точок даних.

Для лінійного ядра K(xi,xj)=xi,xj я можу просто зробитиdot(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.
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
Мені здається, що відповідь Байєра вимагає деяких невеликих модифікацій, щоб відповідати формулі, якщо хтось інший цього потребує:K = scipy.exp(-pairwise_dists**2 / s**2)
chloe

Якщо хтось цікавий, алгоритм, який використовується pdistдуже простий: це просто цикл, реалізований на C, який безпосередньо обчислює відстані очевидним способом , тут робиться циклічне завершення ; відсутність фантазійної векторизації або нічого іншого, що не може автоматично виконати компілятор.
Дугал

11

Як невелике доповнення до відповіді байержа, pdistфункція scipy може безпосередньо обчислити евклідові норми у квадраті, називаючи це як 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')що дає те саме.
користувач1721713

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


Ласкаво просимо на наш сайт! Ми трохи по-іншому акцентуємо увагу на Stack Overflow, оскільки ми, як правило, менше зосереджуємось на коді та більше на основних ідеях, тому, можливо, варто анотувати ваш код або дати коротке уявлення, які ключові ідеї до нього, як деякі з інші відповіді зробили. Це допоможе пояснити, чим ваша відповідь відрізняється від інших.
Срібна рибка

Це буде набагато повільніше, ніж інші відповіді, оскільки він використовує петлі 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.