88 lines
2.7 KiB
Python
Executable File
88 lines
2.7 KiB
Python
Executable File
import numpy as np
|
|
from prml.linear.regression import Regression
|
|
|
|
|
|
class BayesianRegression(Regression):
|
|
"""
|
|
Bayesian regression model
|
|
|
|
w ~ N(w|0, alpha^(-1)I)
|
|
y = X @ w
|
|
t ~ N(t|X @ w, beta^(-1))
|
|
"""
|
|
|
|
def __init__(self, alpha:float=1., beta:float=1.):
|
|
self.alpha = alpha
|
|
self.beta = beta
|
|
self.w_mean = None
|
|
self.w_precision = None
|
|
|
|
def _is_prior_defined(self) -> bool:
|
|
return self.w_mean is not None and self.w_precision is not None
|
|
|
|
def _get_prior(self, ndim:int) -> tuple:
|
|
if self._is_prior_defined():
|
|
return self.w_mean, self.w_precision
|
|
else:
|
|
return np.zeros(ndim), self.alpha * np.eye(ndim)
|
|
|
|
def fit(self, X:np.ndarray, t:np.ndarray):
|
|
"""
|
|
bayesian update of parameters given training dataset
|
|
|
|
Parameters
|
|
----------
|
|
X : (N, n_features) np.ndarray
|
|
training data independent variable
|
|
t : (N,) np.ndarray
|
|
training data dependent variable
|
|
"""
|
|
|
|
mean_prev, precision_prev = self._get_prior(np.size(X, 1))
|
|
|
|
w_precision = precision_prev + self.beta * X.T @ X
|
|
w_mean = np.linalg.solve(
|
|
w_precision,
|
|
precision_prev @ mean_prev + self.beta * X.T @ t
|
|
)
|
|
self.w_mean = w_mean
|
|
self.w_precision = w_precision
|
|
self.w_cov = np.linalg.inv(self.w_precision)
|
|
|
|
def predict(self, X:np.ndarray, return_std:bool=False, sample_size:int=None):
|
|
"""
|
|
return mean (and standard deviation) of predictive distribution
|
|
|
|
Parameters
|
|
----------
|
|
X : (N, n_features) np.ndarray
|
|
independent variable
|
|
return_std : bool, optional
|
|
flag to return standard deviation (the default is False)
|
|
sample_size : int, optional
|
|
number of samples to draw from the predictive distribution
|
|
(the default is None, no sampling from the distribution)
|
|
|
|
Returns
|
|
-------
|
|
y : (N,) np.ndarray
|
|
mean of the predictive distribution
|
|
y_std : (N,) np.ndarray
|
|
standard deviation of the predictive distribution
|
|
y_sample : (N, sample_size) np.ndarray
|
|
samples from the predictive distribution
|
|
"""
|
|
|
|
if sample_size is not None:
|
|
w_sample = np.random.multivariate_normal(
|
|
self.w_mean, self.w_cov, size=sample_size
|
|
)
|
|
y_sample = X @ w_sample.T
|
|
return y_sample
|
|
y = X @ self.w_mean
|
|
if return_std:
|
|
y_var = 1 / self.beta + np.sum(X @ self.w_cov * X, axis=1)
|
|
y_std = np.sqrt(y_var)
|
|
return y, y_std
|
|
return y
|