Các phép biến đổi PCA mà chúng ta đã mô tả ở bài viết trước là các phép biến đổi tuyến tính.
Nói cách khác, mỗi thành phần chính là sự kết hợp tuyến tính của các bước sóng ban đầu.
Giả sử mục đích của PCA là thực hiện một số nhiệm vụ phân loại trên dữ liệu của chúng ta. Khi đó PCA sẽ hữu ích nếu dữ liệu có thể phân tách tuyến tính. Hãy nhìn vào hình ảnh bên dưới. Nó đại diện cho một số điểm dữ liệu. Các điểm dữ liệu được tô màu theo phân loại. Ở phía bên trái, hai lớp được phân tách tuyến tính. Ở phía bên phải, ranh giới phân loại phức tạp hơn, một cái gì đó có thể trông giống như một đa thức bậc cao, một hàm phi tuyến tính ở bất kỳ tỷ lệ nào.
Kernel PCA được phát triển với nỗ lực giúp phân loại dữ liệu có ranh giới quyết định được mô tả bằng hàm phi tuyến tính. Ý tưởng là đi đến một không gian có chiều cao hơn, trong đó ranh giới quyết định trở thành tuyến tính.
Đây là một lập luận đơn giản để hiểu quy trình. Giả sử ranh giới quyết định được mô tả bởi một đa thức bậc ba
[imath]y = a + bx + cx^{2} + dx^{3}[/imath]
. Bây giờ, việc vẽ biểu đồ hàm này trong mặt phẳng x-y thông thường sẽ tạo ra một đường lượn sóng. Một cái gì đó tương tự như ranh giới quyết định được tạo sẵn trong hình bên phải ở trên.
Thay vào đó, giả sử chúng ta đi đến một không gian có số chiều cao hơn, trong đó các trục là
[imath]x, x^{2}, x^{3}[/imath]
và
[imath]y[/imath]
Trong không gian 4D này, đa thức bậc ba trở thành một hàm tuyến tính và ranh giới quyết định trở thành một siêu phẳng. Vì vậy, mẹo là tìm một phép biến đổi phù hợp của các chiều để thử và khôi phục độ tuyến tính của đường biên. Bằng cách này, sự phân tích PCA thông thường lại phù hợp.
Điều này là tốt nhưng, như mọi khi, có một điểm khó khăn. Một tổ hợp phi tuyến tính chung của các biến ban đầu sẽ có một số lượng lớn các biến mới, điều này nhanh chóng làm tăng độ phức tạp tính toán của bài toán.
Hãy thử và giải thích vấn đề này bằng một ví dụ đơn giản khác. Giả sử chúng ta chỉ có hai bước sóng, hãy gọi chúng là
[imath]\lambda_{1}[/imath]
và
[imath]\lambda_{2}[/imath]
. Bây giờ, giả sử chúng ta muốn lấy một kết hợp chung lên đến bậc hai của hai biến này. tập biến mới sau đó sẽ chứa các biến sau:
[imath][\lambda_{1}, \lambda_{2}, \lambda_{1} \lambda_{2}, \lambda_{1}^{2}, \lambda_{2}^{2}][/imath]
. Vì vậy, chúng ta đã đi từ 2 biến đến 5, chỉ bằng cách tìm kiếm một kết hợp bậc hai! Từ một bước sóng chúng có hàng chục hoặc hàng trăm bước sóng, và muốn xem xét các đa thức bậc cao hơn, bạn có thể có ý tưởng về số lượng lớn các biến.
May mắn thay, bây giờ có một giải pháp cho vấn đề này, thường được gọi là thủ thuật hạt nhân.
Hãy gọi
[imath]\mathbf{x}[/imath]
là tập hợp n biến ban đầu, hãy gọi
[imath]\phi (\mathbf{x})[/imath]
tổ hợp phi tuyến tính (ánh xạ) của các biến này thành một tập dữ liệu m> n. Bây giờ chúng ta có thể tính toán hàm kernel
[imath]\kappa (\mathbf{x}) = \phi (\mathbf{x}) \phi^{T}[/imath]
. Lưu ý rằng hàm kernel trong thực tế là một mảng mặc dù chúng ta đang sử dụng ký hiệu hàm.
Bây giờ, hóa ra là hàm kernel đóng vai trò giống như ma trận hiệp phương sai đã làm trong PCA tuyến tính. Điều này có nghĩa là chúng ta có thể tính toán các eigenvalues và eigenvectors của ma trận kernel và đây là các thành phần chính mới của không gian m-chiều nơi chúng ta ánh xạ các biến ban đầu của mình vào.
Thủ thuật kernel được gọi theo cách này vì hàm kernel (ma trận) cho phép chúng ta truy cập các eigenvalues và eigenvectors mà không thực sự tính toán
[imath]\phi (\mathbf{x})[/imath]
một cách rõ ràng. Đây là bước sẽ làm tăng số lượng biến và chúng ta có thể phá vỡ nó bằng cách sử dụng thủ thuật kernel.
Tất nhiên, có những lựa chọn khác nhau cho ma trận kernel. Những cái phổ biến là kernel Gaussian hoặc kernel đa thức. Một kernel đa thức sẽ là lựa chọn phù hợp cho các ranh giới quyết định có hình dạng đa thức, chẳng hạn như ranh giới mà chúng ta đã tạo trong ví dụ trên. Kernel Gaussian là một lựa chọn tốt bất cứ khi nào người ta muốn phân biệt các điểm dữ liệu dựa trên khoảng cách từ trung tâm.
Triển khai KPCA với python
def ker_pca(X, n_components=3, gamma = 0.01):
# Tính khoảng cách euclide của mỗi cặp điểm trong tập dữ liệu
dist = euclidean_distances(X, X, squared=True)
# Tính Gaussian kernel matrix
K = np.exp(-gamma * dist)
Kc = KernelCenterer().fit_transform(K)
# Lấy eigenvalues và eigenvectors của ma trận kernel
eig_vals, eig_vecs = np.linalg.eigh(Kc)
# Đảo đấu của eigenvectors thực thi đầu ra xác định
eig_vecs, _ = extmath.svd_flip(eig_vecs, np.empty_like(eig_vecs).T)
# Nối các eigenvectors tương ứng với n_components eigenvalues cao nhất
Xkpca = np.column_stack([eig_vecs[:,-i] for i in range(1,n_components+1)])
return Xkpca
Dòng đầu tiên tính toán khoảng cách Euclid giữa mỗi cặp điểm trong tập dữ liệu. Ma trận này được chuyển vào dòng thứ hai để tính toán hạt nhân Gaussian. Kernel này còn được gọi là ‘RBF’, là viết tắt của hàm cơ sở hướng tâm và là một trong những hạt nhân mặc định được triển khai trong phiên bản scikit của kernel PCA.
Khi chúng ta có kernel, chúng ta làm theo quy trình tương tự như đối với PCA thông thường. Hãy nhớ kernel đóng vai trò giống như ma trận hiệp phương sai trong PCA tuyến tính, do đó chúng ta có thể tính toán các eigenvalues và eigenvectors của nó và xếp chúng lên đến số lượng thành phần đã chọn mà chúng ta muốn giữ lại.
Triển khai với sklearn để so sánh
kpca1 = KernelPCA(n_components=3, kernel='rbf', gamma=0.01)
Xkpca1 = kpca1.fit_transform(Xstd)
Xkpca2 = ker_pca(Xstd)
with plt.style.context(('ggplot')):
fig, ax = plt.subplots(1, 2, figsize=(14, 6))
#plt.figure(figsize=(8,6))
ax[0].scatter(Xkpca1[:,0], Xkpca1[:,1], s=100, edgecolors='k')
ax[0].set_xlabel('PC 1')
ax[0].set_ylabel('PC 2')
ax[0].set_title('Scikit learn')
ax[1].scatter(Xkpca2[:,0], Xkpca2[:,1], s=100, facecolor = 'b', edgecolors='k')
ax[1].set_xlabel('PC 1')
ax[1].set_ylabel('PC 2')
ax[1].set_title('Our implementation')
plt.show()
Mọi thứ trông có vẻ ổn ..