Làm thế nào để tính toán hạt nhân Gaussian hiệu quả trong numpy [đã đóng]


12

Tôi có một mảng numpy với m cột và n hàng, các cột là kích thước và các cột dữ liệu hàng.

Bây giờ tôi cần tính giá trị kernel cho từng tổ hợp điểm dữ liệu.

Đối với hạt nhân tuyến tính Tôi chỉ có thể làmK(xi,xj)=xi,xjdot(X,X.T)

Làm cách nào tôi có thể tính toán hiệu quả tất cả các giá trị cho Hạt nhân Gaussian K(xi,xj)=expxixj22s2 với một s đã cho ?


1
Chà, nếu bạn không quan tâm quá nhiều đến yếu tố tăng hai lần tính toán, bạn luôn có thể thực hiện và sau đó là trong đó, tất nhiên, là Yếu tố thứ của . Điều này có lẽ không phải là ổn định nhất về số lượng, mặc dù. S=XXTK(xi,xj)=exp((Sii+Sjj2Sij)/s2)Sij(i,j)S
Đức hồng y

2
(Nhiều năm sau) đối với các mảng thưa thớt lớn, xem sklearn.metrics.pairwise.pairwise_distances.html trong scikit-learn.
chối

Câu trả lời:


26

Tôi nghĩ vấn đề chính là để có được khoảng cách cặp đôi một cách hiệu quả. Một khi bạn có rằng phần còn lại là yếu tố khôn ngoan.

Để làm điều này, có lẽ bạn muốn sử dụng scipy. Các chức năng scipy.spatial.distance.pdistlàm những gì bạn cần, và scipy.spatial.distance.squareformcó thể sẽ làm dịu cuộc sống của bạn.

Vì vậy, nếu bạn muốn ma trận kernel bạn làm

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)

Tài liệu có thể được tìm thấy ở đây


3
Dường như với tôi rằng câu trả lời của bayerj đòi hỏi một số sửa đổi nhỏ để phù hợp với công thức, trong trường hợp người khác cần nó:K = scipy.exp(-pairwise_dists**2 / s**2)
chloe

Nếu bất kỳ ai cũng tò mò, thuật toán được sử dụng pdistrất đơn giản: đó chỉ là một vòng lặp được thực hiện bằng C trực tiếp tính toán khoảng cách theo cách rõ ràng , việc lặp được thực hiện ở đây ; không có vector hóa ưa thích hoặc bất cứ điều gì ngoài bất cứ điều gì trình biên dịch có thể tự động thực hiện.
Dougal

11

Là một phụ lục nhỏ cho câu trả lời của bayerj, pdisthàm scipy có thể tính toán trực tiếp các chỉ tiêu euclide bình phương bằng cách gọi nó là pdist(X, 'sqeuclidean'). Mã đầy đủ sau đó có thể được viết hiệu quả hơn như

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
Hoặc đơn giản là pairwise_sq_dists = cdist(X, X, 'sqeuclidean')cho cùng.
dùng1721713

5

Bạn cũng có thể viết mẫu vuông bằng tay:

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 nhưng điều này hoạt động chậm hơn 30%


Đây là phương pháp được đề xuất bởi hồng y trong các bình luận, có thể được tăng tốc một chút bằng cách sử dụng các thao tác tại chỗ. Đó là cách scikit-learn thực hiện nó , với một einsumcuộc gọi cho bạn X2.
Dougal

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)

bằng với

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

Bạn có thể tính toán RBF một cách hiệu quả từ mã lưu ý ở trên rằng giá trị gamma là 1, vì đó là hằng số mà bạn yêu cầu cũng là hằng số tương tự.


Chào mừng đến với trang web của chúng tôi! Chúng tôi có một điểm nhấn hơi khác so với Stack Overflow, ở chỗ chúng tôi thường ít tập trung vào mã hơn và nhiều hơn vào các ý tưởng cơ bản, vì vậy có thể đáng chú thích mã của bạn hoặc đưa ra ý tưởng ngắn gọn về ý tưởng chính của nó, như một số câu trả lời khác đã làm. Điều đó sẽ giúp giải thích câu trả lời của bạn khác với những người khác như thế nào.
Cá bạc

Điều này sẽ chậm hơn nhiều so với các câu trả lời khác vì nó sử dụng các vòng lặp Python chứ không phải vector hóa.
Dougal

-1

Tôi nghĩ rằng điều này sẽ giúp:

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

3
Chào mừng đến với trang web @Kernel. Bạn có thể hiển thị toán học bằng cách đặt biểu thức giữa các dấu $ và sử dụng cú pháp giống như lateX. Và bạn có thể hiển thị mã (có tô sáng cú pháp) bằng cách thụt dòng theo 4 khoảng trắng. Xem trợ giúp chỉnh sửa markdown để biết các hướng dẫn định dạng và faq để biết các hướng dẫn chung hơn.
Antoine Vernet

1
Không phải điều này chỉ lặp lại những gì trong câu hỏi sao?
whuber
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.