123 lines
3.4 KiB
Python
Executable File
123 lines
3.4 KiB
Python
Executable File
import numpy as np
|
|
|
|
|
|
class RelevanceVectorClassifier(object):
|
|
|
|
def __init__(self, kernel, alpha=1.):
|
|
"""
|
|
construct relevance vector classifier
|
|
|
|
Parameters
|
|
----------
|
|
kernel : Kernel
|
|
kernel function to compute components of feature vectors
|
|
alpha : float
|
|
initial precision of prior weight distribution
|
|
"""
|
|
self.kernel = kernel
|
|
self.alpha = alpha
|
|
|
|
def _sigmoid(self, a):
|
|
return np.tanh(a * 0.5) * 0.5 + 0.5
|
|
|
|
def _map_estimate(self, X, t, w, n_iter=10):
|
|
for _ in range(n_iter):
|
|
y = self._sigmoid(X @ w)
|
|
g = X.T @ (y - t) + self.alpha * w
|
|
H = (X.T * y * (1 - y)) @ X + np.diag(self.alpha)
|
|
w -= np.linalg.solve(H, g)
|
|
return w, np.linalg.inv(H)
|
|
|
|
def fit(self, X, t, iter_max=100):
|
|
"""
|
|
maximize evidence with respect ot hyperparameter
|
|
|
|
Parameters
|
|
----------
|
|
X : (sample_size, n_features) ndarray
|
|
input
|
|
t : (sample_size,) ndarray
|
|
corresponding target
|
|
iter_max : int
|
|
maximum number of iterations
|
|
|
|
Attributes
|
|
----------
|
|
X : (N, n_features) ndarray
|
|
relevance vector
|
|
t : (N,) ndarray
|
|
corresponding target
|
|
alpha : (N,) ndarray
|
|
hyperparameter for each weight or training sample
|
|
cov : (N, N) ndarray
|
|
covariance matrix of weight
|
|
mean : (N,) ndarray
|
|
mean of each weight
|
|
"""
|
|
if X.ndim == 1:
|
|
X = X[:, None]
|
|
assert X.ndim == 2
|
|
assert t.ndim == 1
|
|
Phi = self.kernel(X, X)
|
|
N = len(t)
|
|
self.alpha = np.zeros(N) + self.alpha
|
|
mean = np.zeros(N)
|
|
for _ in range(iter_max):
|
|
param = np.copy(self.alpha)
|
|
mean, cov = self._map_estimate(Phi, t, mean, 10)
|
|
gamma = 1 - self.alpha * np.diag(cov)
|
|
self.alpha = gamma / np.square(mean)
|
|
np.clip(self.alpha, 0, 1e10, out=self.alpha)
|
|
if np.allclose(param, self.alpha):
|
|
break
|
|
mask = self.alpha < 1e8
|
|
self.X = X[mask]
|
|
self.t = t[mask]
|
|
self.alpha = self.alpha[mask]
|
|
Phi = self.kernel(self.X, self.X)
|
|
mean = mean[mask]
|
|
self.mean, self.covariance = self._map_estimate(Phi, self.t, mean, 100)
|
|
|
|
def predict(self, X):
|
|
"""
|
|
predict class label
|
|
|
|
Parameters
|
|
----------
|
|
X : (sample_size, n_features)
|
|
input
|
|
|
|
Returns
|
|
-------
|
|
label : (sample_size,) ndarray
|
|
predicted label
|
|
"""
|
|
if X.ndim == 1:
|
|
X = X[:, None]
|
|
assert X.ndim == 2
|
|
phi = self.kernel(X, self.X)
|
|
label = (phi @ self.mean > 0).astype(np.int)
|
|
return label
|
|
|
|
def predict_proba(self, X):
|
|
"""
|
|
probability of input belonging class one
|
|
|
|
Parameters
|
|
----------
|
|
X : (sample_size, n_features) ndarray
|
|
input
|
|
|
|
Returns
|
|
-------
|
|
proba : (sample_size,) ndarray
|
|
probability of predictive distribution p(C1|x)
|
|
"""
|
|
if X.ndim == 1:
|
|
X = X[:, None]
|
|
assert X.ndim == 2
|
|
phi = self.kernel(X, self.X)
|
|
mu_a = phi @ self.mean
|
|
var_a = np.sum(phi @ self.covariance * phi, axis=1)
|
|
return self._sigmoid(mu_a / np.sqrt(1 + np.pi * var_a / 8))
|