Skip to content

Develop batch prediction #89

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 19 commits into from
Apr 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions bayesml/bernoulli/_bernoulli.py
Original file line number Diff line number Diff line change
Expand Up @@ -431,10 +431,7 @@ def calc_pred_dist(self):
return self

def _calc_pred_density(self,x):
if x:
return self.p_theta
else:
return 1.0-self.p_theta
return np.where(x==1,self.p_theta,1.0-self.p_theta)

def make_prediction(self,loss="squared"):
"""Predict a new data point under the given criterion.
Expand Down
88 changes: 46 additions & 42 deletions bayesml/linearregression/_linearregression.py
Original file line number Diff line number Diff line change
Expand Up @@ -326,12 +326,12 @@ class LearnModel(base.Posterior,base.PredictiveMixin):
a positive real number
hn_beta : float
a positive real number
p_m : float
a positive real number
p_lambda : float
a positive real number
p_nu : float
a positive real number
p_ms : numpy ndarray
positive real numbers
p_lambdas : numpy ndarray
positive real numbers
p_nus : numpy ndarray
positive real numbers
"""
def __init__(
self,
Expand All @@ -357,9 +357,9 @@ def __init__(
self.hn_beta = 1.0

# p_params
self.p_m = 0.0
self.p_lambda = 1.0
self.p_nu = 2.0
self.p_ms = 0.0
self.p_lambdas = 1.0
self.p_nus = 2.0

# sample size
self._n = 0
Expand Down Expand Up @@ -510,9 +510,10 @@ def _check_sample_x(self,x):
_check.float_vecs(x,'x',DataFormatError)
if x.shape[-1] != self.c_degree:
raise(DataFormatError(f"x.shape[-1] must be c_degree:{self.c_degree}"))

return x.reshape(-1,self.c_degree)

def _check_sample_y(self,y):
_check.floats(y,'y',DataFormatError)
return _check.floats(y,'y',DataFormatError)

def _check_sample(self,x,y):
self._check_sample_x(x)
Expand Down Expand Up @@ -696,38 +697,37 @@ def get_p_params(self):

Returns
-------
p_params : dict of {str: float}
* ``"p_m"`` : The value of ``self.p_m``
* ``"p_lambda"`` : The value of ``self.p_lambda``
* ``"p_nu"`` : The value of ``self.p_nu``
p_params : dict of {str: numpy ndarray}
* ``"p_ms"`` : The value of ``self.p_ms``
* ``"p_lambdas"`` : The value of ``self.p_lambdas``
* ``"p_nus"`` : The value of ``self.p_nus``
"""
return {"p_m":self.p_m, "p_lambda":self.p_lambda, "p_nu":self.p_nu}
return {"p_ms":self.p_ms, "p_lambdas":self.p_lambdas, "p_nus":self.p_nus}

def calc_pred_dist(self, x):
"""Calculate the parameters of the predictive distribution.

Parameters
----------
x : numpy ndarray
1 dimensional float array whose size is ``self.c_degree``
float array. The size along the last dimension must conincides with the c_degree.
If you want to use a constant term, it should be included in x.
"""
_check.float_vec(x,'x',DataFormatError)
if x.shape != (self.c_degree,):
raise(DataFormatError("x must be a 1 dimensional float array whose size coincide with ``self.c_degree``"))
self.p_m = x @ self.hn_mu_vec
self.p_lambda = self.hn_alpha / self.hn_beta / (1.0 + x @ np.linalg.solve(self.hn_lambda_mat,x))
self.p_nu = 2.0 * self.hn_alpha
x = self._check_sample_x(x)
self.p_ms = x @ self.hn_mu_vec
self.p_lambdas = self.hn_alpha / self.hn_beta / (1.0 + np.sum(x.T * np.linalg.solve(self.hn_lambda_mat,x.T),axis=0))
self.p_nus = np.ones(x.shape[0]) * 2.0 * self.hn_alpha
return self

def _calc_pred_dist(self, x):
"""Calculate predictive distribution without check."""
self.p_m = x @ self.hn_mu_vec
self.p_lambda = self.hn_alpha / self.hn_beta / (1.0 + x @ np.linalg.solve(self.hn_lambda_mat,x))
self.p_nu = 2.0 * self.hn_alpha
self.p_ms = x @ self.hn_mu_vec
self.p_lambdas = self.hn_alpha / self.hn_beta / (1.0 + np.sum(x.T * np.linalg.solve(self.hn_lambda_mat,x.T),axis=0))
self.p_nus = np.ones(x.shape[0]) * 2.0 * self.hn_alpha
return self

def _calc_pred_density(self,y):
return ss_t.pdf(y,loc=self.p_m, scale=1.0/np.sqrt(self.p_lambda), df=self.p_nu)
return ss_t.pdf(y,loc=self.p_ms, scale=1.0/np.sqrt(self.p_lambdas), df=self.p_nus)

def make_prediction(self,loss="squared"):
"""Predict a new data point under the given criterion.
Expand All @@ -740,20 +740,21 @@ def make_prediction(self,loss="squared"):

Returns
-------
Predicted_value : {float, rv_frozen}
The predicted value under the given loss function.
Predicted_values : {numpy ndarray, rv_frozen}
The predicted values under the given loss function.
The size of the predicted values is the same as the sample size of x when you called calc_pred_dist(x).
If the loss function is \"KL\", the predictive distribution itself will be returned
as rv_frozen object of scipy.stats.
as rv_frozen object of scipy.stats. The rv_frozen object supports broadcasting.

See Also
--------
scipy.stats.rv_continuous
scipy.stats.rv_discrete
"""
if loss == "squared" or loss == "0-1" or loss == "abs":
return self.p_m
return self.p_ms
elif loss == "KL":
return ss_t(loc=self.p_m, scale=1.0/np.sqrt(self.p_lambda), df=self.p_nu)
return ss_t(loc=self.p_ms, scale=1.0/np.sqrt(self.p_lambdas), df=self.p_nus)
else:
raise(CriteriaError("Unsupported loss function! "
"This function supports \"squared\", \"0-1\", \"abs\", and \"KL\"."))
Expand All @@ -764,7 +765,8 @@ def pred_and_update(self,x,y,loss="squared"):
Parameters
----------
x : numpy ndarray
1 dimensional float array whose size is ``self.c_degree``.
float array. The size along the last dimension must conincides with the c_degree.
If you want to use a constant term, it should be included in x.
y : float

loss : str, optional
Expand All @@ -773,8 +775,9 @@ def pred_and_update(self,x,y,loss="squared"):

Returns
-------
Predicted_value : {float, rv_frozen}
The predicted value under the given loss function.
Predicted_values : {numpy ndarray, rv_frozen}
The predicted values under the given loss function.
The size of the predicted values is the same as the sample size of x when you called calc_pred_dist(x).
If the loss function is \"KL\", the predictive distribution itself will be returned
as rv_frozen object of scipy.stats.
"""
Expand Down Expand Up @@ -808,11 +811,12 @@ def calc_pred_var(self):

Returns
-------
var : float
The variance of the predictive distribution.
vars : numpy ndarray
The variances of the predictive distribution.
The size of the vars is the same as the sample size of x when you called calc_pred_dist(x).
"""
if self.p_nu > 2:
return self.p_nu / self.p_lambda / (self.p_nu-2)
else:
warnings.warn("Variance of the predictive distribution cannot defined for the current p_nu.",ResultWarning)
return None
indices = self.p_nus > 2
var = np.empty(self.p_nus.shape[0])
var[indices] = self.p_nus[indices] / self.p_lambdas[indices] / (self.p_nus[indices]-2)
var[~indices] = np.nan
return var
Loading