Skip to content

Commit 39d38b7

Browse files
authored
Add PyDocStyle Support (#951)
1 parent f6c6825 commit 39d38b7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+828
-292
lines changed

docs/source/conf.py

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#!/usr/bin/env python3
2+
"""Sphinx configuration for PyMC Marketing Docs."""
23

34
import os
45

docs/source/notebooks/mmm/mmm_time_varying_media_example.ipynb

+2-3
Original file line numberDiff line numberDiff line change
@@ -4550,8 +4550,7 @@
45504550
"def plot_posterior(\n",
45514551
" posterior, figsize=(15, 8), path_color=\"blue\", hist_color=\"blue\", **kwargs\n",
45524552
"):\n",
4553-
" \"\"\"\n",
4554-
" Plot the posterior distribution of a stochastic process.\n",
4553+
" \"\"\"Plot the posterior distribution of a stochastic process.\n",
45554554
"\n",
45564555
" Parameters\n",
45574556
" ----------\n",
@@ -4565,8 +4564,8 @@
45654564
" Color of the histogram.\n",
45664565
" **kwargs\n",
45674566
" Additional keyword arguments to pass to the plotting functions.\n",
4568-
" \"\"\"\n",
45694567
"\n",
4568+
" \"\"\"\n",
45704569
" # Calculate the expected value (mean) across all draws and chains for each date\n",
45714570
" expected_value = posterior.mean(dim=(\"draw\", \"chain\"))\n",
45724571
"\n",

docs/source/uml/classes_clv.png

569 Bytes
Loading

docs/source/uml/classes_mmm.png

890 Bytes
Loading

pymc_marketing/__init__.py

+2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
14+
"""PyMC Marketing."""
15+
1416
from pymc_marketing import clv, mmm
1517
from pymc_marketing.version import __version__
1618

pymc_marketing/clv/__init__.py

+2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
14+
"""CLV models and utilities."""
15+
1416
from pymc_marketing.clv.models import (
1517
BetaGeoModel,
1618
GammaGammaModel,

pymc_marketing/clv/distributions.py

+25-13
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
14+
"""Distributions for the CLV module."""
15+
1416
import numpy as np
1517
import pymc as pm
1618
import pytensor.tensor as pt
@@ -80,9 +82,9 @@ def _supp_shape_from_params(*args, **kwargs):
8082

8183

8284
class ContNonContract(PositiveContinuous):
83-
r"""
84-
Individual-level model for the customer lifetime value. See equation (3)
85-
from Fader et al. (2005) [1]_.
85+
r"""Individual-level model for the customer lifetime value.
86+
87+
See equation (3) from Fader et al. (2005) [1]_.
8688
8789
.. math::
8890
@@ -100,15 +102,18 @@ class ContNonContract(PositiveContinuous):
100102
.. [1] Fader, Peter S., Bruce GS Hardie, and Ka Lok Lee. "“Counting your customers”
101103
the easy way: An alternative to the Pareto/NBD model." Marketing science
102104
24.2 (2005): 275-284.
105+
103106
"""
104107

105108
rv_op = continuous_non_contractual
106109

107110
@classmethod
108111
def dist(cls, lam, p, T, **kwargs):
112+
"""Get the distribution from the parameters."""
109113
return super().dist([lam, p, T], **kwargs)
110114

111115
def logp(value, lam, p, T):
116+
"""Log-likelihood of the distribution."""
112117
t_x = value[..., 0]
113118
x = value[..., 1]
114119

@@ -206,10 +211,10 @@ def _supp_shape_from_params(*args, **kwargs):
206211

207212

208213
class ContContract(PositiveContinuous):
209-
r"""
210-
Distribution class of a continuous contractual data-generating process,
211-
that is where purchases can occur at any time point (continuous) and
212-
churning/dropping out is explicit (contractual).
214+
r"""Distribution class of a continuous contractual data-generating process.
215+
216+
That is where purchases can occur at any time point (continuous) and churning/dropping
217+
out is explicit (contractual).
213218
214219
.. math::
215220
@@ -228,9 +233,11 @@ class ContContract(PositiveContinuous):
228233

229234
@classmethod
230235
def dist(cls, lam, p, T, **kwargs):
236+
"""Get the distribution from the parameters."""
231237
return super().dist([lam, p, T], **kwargs)
232238

233239
def logp(value, lam, p, T):
240+
"""Log-likelihood of the distribution."""
234241
t_x = value[..., 0]
235242
x = value[..., 1]
236243
churn = value[..., 2]
@@ -358,9 +365,9 @@ def _supp_shape_from_params(*args, **kwargs):
358365

359366

360367
class ParetoNBD(PositiveContinuous):
361-
r"""
362-
Population-level distribution class for a continuous, non-contractual, Pareto/NBD process,
363-
based on Schmittlein, et al. in [2]_.
368+
r"""Population-level distribution class for a continuous, non-contractual, Pareto/NBD process.
369+
370+
It is based on Schmittlein, et al. in [2]_.
364371
365372
The likelihood function is derived from equations (22) and (23) of [3]_, with terms
366373
rearranged for numerical stability.
@@ -403,15 +410,18 @@ class ParetoNBD(PositiveContinuous):
403410
.. [3] Fader, Peter & G. S. Hardie, Bruce (2005).
404411
"A Note on Deriving the Pareto/NBD Model and Related Expressions."
405412
http://brucehardie.com/notes/009/pareto_nbd_derivations_2005-11-05.pdf
413+
406414
""" # noqa: E501
407415

408416
rv_op = pareto_nbd
409417

410418
@classmethod
411419
def dist(cls, r, alpha, s, beta, T, **kwargs):
420+
"""Get the distribution from the parameters."""
412421
return super().dist([r, alpha, s, beta, T], **kwargs)
413422

414423
def logp(value, r, alpha, s, beta, T):
424+
"""Log-likelihood of the distribution."""
415425
t_x = value[..., 0]
416426
x = value[..., 1]
417427

@@ -555,9 +565,9 @@ def _supp_shape_from_params(*args, **kwargs):
555565

556566

557567
class BetaGeoBetaBinom(Discrete):
558-
r"""
559-
Population-level distribution class for a discrete, non-contractual, Beta-Geometric/Beta-Binomial process,
560-
based on equation(5) from Fader, et al. in [1]_.
568+
r"""Population-level distribution class for a discrete, non-contractual, Beta-Geometric/Beta-Binomial process.
569+
570+
It is based on equation(5) from Fader, et al. in [1]_.
561571
562572
.. math::
563573
@@ -584,9 +594,11 @@ class BetaGeoBetaBinom(Discrete):
584594

585595
@classmethod
586596
def dist(cls, alpha, beta, gamma, delta, T, **kwargs):
597+
"""Get the distribution from the parameters."""
587598
return super().dist([alpha, beta, gamma, delta, T], **kwargs)
588599

589600
def logp(value, alpha, beta, gamma, delta, T):
601+
"""Log-likelihood of the distribution."""
590602
t_x = pt.atleast_1d(value[..., 0])
591603
x = pt.atleast_1d(value[..., 1])
592604
scalar_case = t_x.type.broadcastable == (True,)

pymc_marketing/clv/models/__init__.py

+3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
14+
15+
"""CLV models."""
16+
1417
from pymc_marketing.clv.models.basic import CLVModel
1518
from pymc_marketing.clv.models.beta_geo import BetaGeoModel
1619
from pymc_marketing.clv.models.gamma_gamma import (

pymc_marketing/clv/models/basic.py

+21-7
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
14+
"""CLV Model base class."""
15+
1416
import json
1517
import warnings
1618
from collections.abc import Sequence
@@ -32,6 +34,8 @@
3234

3335

3436
class CLVModel(ModelBuilder):
37+
"""CLV Model base class."""
38+
3539
_model_type = "CLVModel"
3640

3741
@validate_call(config=ConfigDict(arbitrary_types_allowed=True))
@@ -69,6 +73,7 @@ def _validate_cols(
6973
raise ValueError(f"Column {required_col} has duplicate entries")
7074

7175
def __repr__(self) -> str:
76+
"""Representation of the model."""
7277
if not hasattr(self, "model"):
7378
return self._model_type
7479
else:
@@ -89,7 +94,7 @@ def fit( # type: ignore
8994
fit_method: str = "mcmc",
9095
**kwargs,
9196
) -> az.InferenceData:
92-
"""Infer model posterior
97+
"""Infer model posterior.
9398
9499
Parameters
95100
----------
@@ -99,8 +104,8 @@ def fit( # type: ignore
99104
- "map": Finds maximum a posteriori via `pymc.find_MAP`
100105
kwargs:
101106
Other keyword arguments passed to the underlying PyMC routines
102-
"""
103107
108+
"""
104109
self.build_model() # type: ignore
105110

106111
if fit_method == "mcmc":
@@ -120,8 +125,8 @@ def fit( # type: ignore
120125
return self.idata
121126

122127
def _fit_mcmc(self, **kwargs) -> az.InferenceData:
123-
"""
124-
Fit a model using the data passed as a parameter.
128+
"""Fit a model using the data passed as a parameter.
129+
125130
Sets attrs to inference data of the model.
126131
127132
@@ -138,6 +143,7 @@ def _fit_mcmc(self, **kwargs) -> az.InferenceData:
138143
-------
139144
self : az.InferenceData
140145
returns inference data of the fitted model.
146+
141147
"""
142148
sampler_config = {}
143149
if self.sampler_config is not None:
@@ -146,7 +152,7 @@ def _fit_mcmc(self, **kwargs) -> az.InferenceData:
146152
return pm.sample(**sampler_config, model=self.model)
147153

148154
def _fit_MAP(self, **kwargs) -> az.InferenceData:
149-
"""Find model maximum a posteriori using scipy optimizer"""
155+
"""Find model maximum a posteriori using scipy optimizer."""
150156
model = self.model
151157
map_res = pm.find_MAP(model=model, **kwargs)
152158
# Filter non-value variables
@@ -162,8 +168,8 @@ def _fit_MAP(self, **kwargs) -> az.InferenceData:
162168

163169
@classmethod
164170
def load(cls, fname: str):
165-
"""
166-
Creates a ModelBuilder instance from a file,
171+
"""Create a ModelBuilder instance from a file.
172+
167173
Loads inference data for the model.
168174
169175
Parameters
@@ -179,12 +185,14 @@ def load(cls, fname: str):
179185
------
180186
ValueError
181187
If the inference data that is loaded doesn't match with the model.
188+
182189
Examples
183190
--------
184191
>>> class MyModel(ModelBuilder):
185192
>>> ...
186193
>>> name = './mymodel.nc'
187194
>>> imported_model = MyModel.load(name)
195+
188196
"""
189197
filepath = Path(str(fname))
190198
idata = from_netcdf(filepath)
@@ -242,6 +250,7 @@ def thin_fit_result(self, keep_every: int):
242250

243251
@property
244252
def default_sampler_config(self) -> dict:
253+
"""Default sampler configuration."""
245254
return {}
246255

247256
@property
@@ -250,6 +259,7 @@ def _serializable_model_config(self) -> dict:
250259

251260
@property
252261
def fit_result(self) -> Dataset:
262+
"""Get the fit result."""
253263
if self.idata is None or "posterior" not in self.idata:
254264
raise RuntimeError("The model hasn't been fit yet, call .fit() first")
255265
return self.idata["posterior"]
@@ -265,6 +275,7 @@ def fit_result(self, res: az.InferenceData) -> None:
265275
self.idata.posterior = res
266276

267277
def fit_summary(self, **kwargs):
278+
"""Compute the summary of the fit result."""
268279
res = self.fit_result
269280
# Map fitting only gives one value, so we return it. We use arviz
270281
# just to get it nicely into a DataFrame
@@ -278,10 +289,13 @@ def fit_summary(self, **kwargs):
278289

279290
@property
280291
def output_var(self):
292+
"""Output variable of the model."""
281293
pass
282294

283295
def _generate_and_preprocess_model_data(self, *args, **kwargs):
296+
"""Generate and preprocess model data."""
284297
pass
285298

286299
def _data_setter(self):
300+
"""Set the data for the model."""
287301
pass

0 commit comments

Comments
 (0)