先看看SSKDA 的formulations,后面附代码
'''
Semi-supervised Kernel Discriminant Analysis
Deniu He
2023-04-04
'''
import numpy as np
from sklearn.datasets import load_iris
from sklearn import datasets
from sklearn.metrics.pairwise import rbf_kernel
from sklearn.metrics.pairwise import pairwise_kernels
import matplotlib.pyplot as plt
from numpy import linalg as LA
from sklearn.neighbors import kneighbors_graph
class SSKDA():
def __init__(self, n_components=None, kernel=None, gamma=None):
self.n_components = n_components
self.Beta = None
self.X = None
self.labeled = None
self.gamma = gamma
if kernel is not None:
self.kernel = None
else:
self.kernel = 'linear'
def fit(self, X, y, labeled_index, unlabeled_index, miu = 1e-3):
self.nSample = X.shape[0]
self.y = y
self.X = X
self.labels = np.unique(y)
self.nClass = len(self.labels)
self.labeled = labeled_index
self.unlabeled = unlabeled_index
self.miu = miu
self.index_total = np.arange(X.shape[0])
self.nLabeled = len(labeled_index)
self.Kernel_total = rbf_kernel(X=X, gamma=self.gamma)
self.Kernel_L_T = self.Kernel_total[np.ix_(self.labeled, self.index_total)]
graph = kneighbors_graph(X=X, n_neighbors=4, mode='connectivity', include_self=True)
S = graph.toarray()
D = np.diag(S)
self.L = D - S
self.N = self.get_N()
self.H = self.get_H()
# print("N::",self.N.shape)
# print("H::",self.H.shape)
# print(self.miu)
# print("self.Kernel_L_U ::",self.Kernel_L_T.shape )
# print("self.L",self.L.shape)
self.N_KLK = self.N + self.miu * self.Kernel_L_T @ self.L @ self.Kernel_L_T.T
epsilon = 1e-08
eig_val, eig_vec = LA.eigh(LA.inv(self.N_KLK + epsilon * np.eye(self.nLabeled))@self.H)
ord_idx = eig_val.argsort()[::-1] # sort eigenvalues in descending order (largest eigenvalue first)
eig_val = eig_val[ord_idx]
eig_vec = eig_vec[:,ord_idx]
if self.n_components is not None:
self.Beta = eig_vec[:,:self.n_components]
else:
self.Beta = eig_vec[:,:self.nClass-1]
def transform(self, X):
# print(self.labeled.shape)
# print(X.shape)
# print(self.X.shape)
Kernel_train_input = rbf_kernel(X=self.X[self.labeled], Y=X, gamma=self.gamma)
X_transform = self.Beta.T @ Kernel_train_input
return X_transform.T
def get_H(self):
H = np.zeros((self.nLabeled, self.nLabeled))
M_star = self.Kernel_total[np.ix_(self.labeled, self.labeled)]
M_star = M_star.sum(axis=1)
M_star = M_star.reshape((-1,1))
M_star = (1 / self.nSample) * M_star
for i, lab in enumerate(self.labels):
idx_list = np.where(self.y[self.labeled] == lab)[0]
idx_list = self.labeled[idx_list] # 真实索引
Ki = self.Kernel_total[np.ix_(self.labeled, idx_list)]
M_c = Ki.sum(axis=1)
M_c = M_c.reshape((-1,1))
M_c = (1 / len(idx_list)) * M_c
H += len(idx_list) * (M_c - M_star) @ (M_c - M_star).T
return H
def get_N(self):
N = np.zeros((self.nLabeled, self.nLabeled))
for i, lab in enumerate(self.labels):
idx_list = np.where(self.y[self.labeled] == lab)[0]
Ki = self.Kernel_total[np.ix_(self.labeled, idx_list)]
N += Ki @ (np.eye(len(idx_list)) - np.ones(len(idx_list)) * (1/ len(idx_list))) @ Ki.T
N += np.eye(self.nLabeled) * 1e-8
return N
if __name__ == '__main__':
X, y = datasets.make_circles(n_samples=400, shuffle=True, noise=0.01, random_state=42)
plt.scatter(X[:,0], X[:,1], c=y)
plt.show()
labeled_idx = np.random.choice(np.arange(400), size=20, replace=False)
unlabeled_idx = list(np.arange(400))
for idx in labeled_idx:
unlabeled_idx.remove(idx)
unlabeled_idx = np.asarray(unlabeled_idx)
sskda = SSKDA(n_components=2, kernel='rbf', gamma=0.01)
sskda.fit(X=X,y=y,labeled_index=labeled_idx, unlabeled_index=unlabeled_idx)
X_transformed = sskda.transform(X=X)
plt.scatter(X_transformed[:,0], X_transformed[:,1], c=y)
plt.show()
总共有400个点(样本)
使用20个标记样本的半监督的结果:
使用100个标记样本的半监督结果: