From d72be71a8d7324b4d3f37e371c8537491e245961 Mon Sep 17 00:00:00 2001 From: Jose Ortiz Date: Thu, 4 May 2023 15:01:33 -0700 Subject: [PATCH 1/4] Implemented NormalFixedMean --- ngboost/distns/__init__.py | 2 +- ngboost/distns/normal.py | 62 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/ngboost/distns/__init__.py b/ngboost/distns/__init__.py index 5468073..a492047 100644 --- a/ngboost/distns/__init__.py +++ b/ngboost/distns/__init__.py @@ -7,6 +7,6 @@ from .laplace import Laplace # NOQA from .lognormal import LogNormal # NOQA from .multivariate_normal import MultivariateNormal # NOQA -from .normal import Normal, NormalFixedVar # NOQA +from .normal import Normal, NormalFixedMean, NormalFixedVar # NOQA from .poisson import Poisson # NOQA from .t import T, TFixedDf, TFixedDfFixedVar # NOQA diff --git a/ngboost/distns/normal.py b/ngboost/distns/normal.py index 62f7210..b8fe1e8 100644 --- a/ngboost/distns/normal.py +++ b/ngboost/distns/normal.py @@ -150,3 +150,65 @@ def __init__(self, params): def fit(Y): m, _ = sp.stats.norm.fit(Y) return m + + +# ### Fixed Mean Normal ### +class NormalFixedMeanLogScore(LogScore): + def score(self, Y): + return -self.dist.logpdf(Y) + + def d_score(self, Y): + D = np.zeros((len(Y), 1)) + D[:, 0] = 1 - ((self.loc - Y) ** 2) / self.var + return D + + def metric(self): + FI = np.zeros((self.var.shape[0], 1, 1)) + FI[:, 0, 0] = 2 + return FI + + +class NormalFixedMeanCRPScore(CRPScore): + def score(self, Y): + Z = (Y - self.loc) / self.scale + return self.scale * ( + Z * (2 * sp.stats.norm.cdf(Z) - 1) + + 2 * sp.stats.norm.pdf(Z) + - 1 / np.sqrt(np.pi) + ) + + def d_score(self, Y): + Z = (Y - self.loc) / self.scale + D = np.zeros((len(Y), 1)) + D[:, 0] = self.score(Y) + (Y - self.loc) * -1 * (2 * sp.stats.norm.cdf(Z) - 1) + return D + + def metric(self): + I = np.c_[self.var] + I = I.reshape((self.var.shape[0], 1, 1)) + I = 1 / (2 * np.sqrt(np.pi)) * I + return I + + +class NormalFixedMean(Normal): + """ + Implements the normal distribution with mean=0 for NGBoost. + + The fixed-mean normal distribution has one parameter, scale which is the standard deviation. + This distribution has both LogScore and CRPScore implemented for it. + """ + + n_params = 1 + scores = [NormalFixedMeanLogScore, NormalFixedMeanCRPScore] + + # pylint: disable=super-init-not-called + def __init__(self, params): + self.loc = np.zeros_like(params[0]) + self.var = params[0] ** 2 + self.scale = params[0] + self.shape = self.loc.shape + self.dist = dist(loc=self.loc, scale=self.scale) + + def fit(Y): + _, s = sp.stats.norm.fit(Y) + return s From 1c9823c685360effc217c8b2cfc3332cbb5810f3 Mon Sep 17 00:00:00 2001 From: Jose Ortiz Date: Thu, 4 May 2023 15:18:42 -0700 Subject: [PATCH 2/4] Added NormalFixedVar and NormalFixedMean to test_distns.py --- tests/test_distns.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/tests/test_distns.py b/tests/test_distns.py index 4ece8e4..f0a03ff 100644 --- a/tests/test_distns.py +++ b/tests/test_distns.py @@ -14,6 +14,8 @@ LogNormal, MultivariateNormal, Normal, + NormalFixedMean, + NormalFixedVar, T, TFixedDf, TFixedDfFixedVar, @@ -33,7 +35,18 @@ @pytest.mark.slow @pytest.mark.parametrize( "dist", - [Normal, LogNormal, Exponential, Gamma, T, TFixedDf, TFixedDfFixedVar, Cauchy], + [ + Normal, + NormalFixedVar, + NormalFixedMean, + LogNormal, + Exponential, + Gamma, + T, + TFixedDf, + TFixedDfFixedVar, + Cauchy, + ], ) @pytest.mark.parametrize( "learner", From 610a005808976fc3791082d10a0c7523cecc8d31 Mon Sep 17 00:00:00 2001 From: Jose Ortiz Date: Mon, 8 May 2023 12:54:41 -0700 Subject: [PATCH 3/4] Match log(sigma) parameterization of Normal class --- ngboost/distns/normal.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ngboost/distns/normal.py b/ngboost/distns/normal.py index b8fe1e8..35bbdfd 100644 --- a/ngboost/distns/normal.py +++ b/ngboost/distns/normal.py @@ -204,8 +204,8 @@ class NormalFixedMean(Normal): # pylint: disable=super-init-not-called def __init__(self, params): self.loc = np.zeros_like(params[0]) - self.var = params[0] ** 2 - self.scale = params[0] + self.scale = np.exp(params[0]) + self.var = self.scale**2 self.shape = self.loc.shape self.dist = dist(loc=self.loc, scale=self.scale) From 1d30583086a988d0a87a7b98515f8e80804d82f0 Mon Sep 17 00:00:00 2001 From: Joey Ortiz Date: Wed, 14 Feb 2024 09:34:39 -0800 Subject: [PATCH 4/4] Update __init__.py Linter is demanding a blank line for ending a file (sigh) --- ngboost/distns/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ngboost/distns/__init__.py b/ngboost/distns/__init__.py index e2e2526..05e9412 100644 --- a/ngboost/distns/__init__.py +++ b/ngboost/distns/__init__.py @@ -30,4 +30,4 @@ "T", "TFixedDf", "TFixedDfFixedVar", -] \ No newline at end of file +]