Skip to content
2 changes: 1 addition & 1 deletion docs/source/notebooks/clv/bg_nbd.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@
"id": "0a5fc96b-eedd-43ae-bd70-5ae388f1f636",
"metadata": {},
"source": [
"Notice the additional `phi_dropout` and `kappa_dropout` priors. These were added to the default configuration to improve performance, but can be omitted when specifying a custom `model_config` with `a_prior` and `b_prior`.\n",
"Notice the additional `phi_dropout` and `kappa_dropout` priors. These were added to the default configuration to improve performance, but can be omitted when specifying a custom `model_config` with `a` and `b`.\n",
"\n",
"The specified model structure can also be visualized:"
]
Expand Down
8 changes: 4 additions & 4 deletions docs/source/notebooks/clv/clv_quickstart.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -576,10 +576,10 @@
"outputs": [],
"source": [
"model_config = {\n",
" \"a_prior\": Prior(\"HalfNormal\", sigma=10),\n",
" \"b_prior\": Prior(\"HalfNormal\", sigma=10),\n",
" \"alpha_prior\": Prior(\"HalfNormal\", sigma=10),\n",
" \"r_prior\": Prior(\"HalfNormal\", sigma=10),\n",
" \"a\": Prior(\"HalfNormal\", sigma=10),\n",
" \"b\": Prior(\"HalfNormal\", sigma=10),\n",
" \"alpha\": Prior(\"HalfNormal\", sigma=10),\n",
" \"r\": Prior(\"HalfNormal\", sigma=10),\n",
"}"
]
},
Expand Down
8 changes: 4 additions & 4 deletions docs/source/notebooks/clv/dev/beta_geo_beta_binom.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,10 @@
],
"source": [
"model_config = {\n",
" \"alpha_prior\": Prior(\"HalfFlat\"),\n",
" \"beta_prior\": Prior(\"HalfFlat\"),\n",
" \"gamma_prior\": Prior(\"HalfFlat\"),\n",
" \"delta_prior\": Prior(\"HalfFlat\"),\n",
" \"alpha\": Prior(\"HalfFlat\"),\n",
" \"beta\": Prior(\"HalfFlat\"),\n",
" \"gamma\": Prior(\"HalfFlat\"),\n",
" \"delta\": Prior(\"HalfFlat\"),\n",
"}\n",
"\n",
"model = BetaGeoBetaBinomModel(data=data,model_config=model_config)\n",
Expand Down
2 changes: 1 addition & 1 deletion docs/source/notebooks/clv/mbg_nbd.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@
"id": "0a5fc96b-eedd-43ae-bd70-5ae388f1f636",
"metadata": {},
"source": [
"Notice the additional `phi_dropout` and `kappa_dropout` priors. These were added to the default configuration to improve performance, but can be omitted when specifying a custom `model_config` with `a_prior` and `b_prior`.\n",
"Notice the additional `phi_dropout` and `kappa_dropout` priors. These were added to the default configuration to improve performance, but can be omitted when specifying a custom `model_config` with `a` and `b`.\n",
"\n",
"The specified model structure can also be visualized:"
]
Expand Down
8 changes: 4 additions & 4 deletions docs/source/notebooks/clv/pareto_nbd.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -588,10 +588,10 @@
"outputs": [],
"source": [
"flat_config = {\n",
" \"r_prior\": Prior(\"HalfFlat\"),\n",
" \"alpha_prior\": Prior(\"HalfFlat\"),\n",
" \"s_prior\": Prior(\"HalfFlat\"),\n",
" \"beta_prior\": Prior(\"HalfFlat\"),\n",
" \"r\": Prior(\"HalfFlat\"),\n",
" \"alpha\": Prior(\"HalfFlat\"),\n",
" \"s\": Prior(\"HalfFlat\"),\n",
" \"beta\": Prior(\"HalfFlat\"),\n",
"}\n",
"\n",
"pnbd_pymc = clv.ParetoNBDModel(data=rfm_data, model_config=flat_config)"
Expand Down
29 changes: 29 additions & 0 deletions pymc_marketing/clv/models/basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,19 @@
non_distributions: list[str] | None = None,
):
model_config = model_config or {}

deprecated_keys = [key for key in model_config if key.endswith("_prior")]
for key in deprecated_keys:
new_key = key.replace("_prior", "")
warnings.warn(

Check warning on line 54 in pymc_marketing/clv/models/basic.py

View check run for this annotation

Codecov / codecov/patch

pymc_marketing/clv/models/basic.py#L53-L54

Added lines #L53 - L54 were not covered by tests
f"The key '{key}' in model_config is deprecated and will be removed in future versions."
f"Use '{new_key}' instead.",
DeprecationWarning,
stacklevel=2,
)

model_config[new_key] = model_config.pop(key)

Check warning on line 61 in pymc_marketing/clv/models/basic.py

View check run for this annotation

Codecov / codecov/patch

pymc_marketing/clv/models/basic.py#L61

Added line #L61 was not covered by tests

model_config = parse_model_config(
model_config,
non_distributions=non_distributions,
Expand Down Expand Up @@ -279,12 +292,28 @@
model_config=json.loads(idata.attrs["model_config"]), # type: ignore
sampler_config=json.loads(idata.attrs["sampler_config"]),
)

model.idata = idata
model._rename_posterior_variables()

Check warning on line 297 in pymc_marketing/clv/models/basic.py

View check run for this annotation

Codecov / codecov/patch

pymc_marketing/clv/models/basic.py#L297

Added line #L297 was not covered by tests

model.build_model() # type: ignore
if model.id != idata.attrs["id"]:
raise ValueError(f"Inference data not compatible with {cls._model_type}")
return model

def _rename_posterior_variables(self):
"""Rename variables in the posterior group to remove the _prior suffix.
This is used to support the old model configuration format, which used
to include a _prior suffix for each parameter.
"""
prior_vars = [

Check warning on line 310 in pymc_marketing/clv/models/basic.py

View check run for this annotation

Codecov / codecov/patch

pymc_marketing/clv/models/basic.py#L310

Added line #L310 was not covered by tests
var for var in self.idata.posterior.data_vars if var.endswith("_prior")
]
rename_dict = {var: var.replace("_prior", "") for var in prior_vars}
self.idata.posterior = self.idata.posterior.rename(rename_dict)
return self.idata.posterior

Check warning on line 315 in pymc_marketing/clv/models/basic.py

View check run for this annotation

Codecov / codecov/patch

pymc_marketing/clv/models/basic.py#L313-L315

Added lines #L313 - L315 were not covered by tests

def thin_fit_result(self, keep_every: int):
"""Return a copy of the model with a thinned fit result.
Expand Down
100 changes: 46 additions & 54 deletions pymc_marketing/clv/models/beta_geo.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,14 @@
* `T`: Time between the first purchase and the end of the observation period
model_config : dict, optional
Dictionary of model prior parameters:
* `alpha_prior`: Scale parameter for time between purchases; defaults to `Prior("Weibull", alpha=2, beta=10)`
* `r_prior`: Shape parameter for time between purchases; defaults to `Prior("Weibull", alpha=2, beta=1)`
* `a_prior`: Shape parameter of dropout process; defaults to `phi_purchase_prior` * `kappa_purchase_prior`
* `b_prior`: Shape parameter of dropout process; defaults to `1-phi_dropout_prior` * `kappa_dropout_prior`
* `phi_dropout_prior`: Nested prior for a and b priors; defaults to `Prior("Uniform", lower=0, upper=1)`
* `kappa_dropout_prior`: Nested prior for a and b priors; defaults to `Prior("Pareto", alpha=1, m=1)`
* `purchase_covariates_prior`: Coefficients for purchase rate covariates; defaults to `Normal(0, 3)`
* `dropout_covariates_prior`: Coefficients for dropout covariates; defaults to `Normal.dist(0, 3)`
* `alpha`: Scale parameter for time between purchases; defaults to `Prior("Weibull", alpha=2, beta=10)`
* `r`: Shape parameter for time between purchases; defaults to `Prior("Weibull", alpha=2, beta=1)`
* `a`: Shape parameter of dropout process; defaults to `phi_purchase` * `kappa_purchase`
* `b`: Shape parameter of dropout process; defaults to `1-phi_dropout` * `kappa_dropout`
* `phi_dropout`: Nested prior for a and b priors; defaults to `Prior("Uniform", lower=0, upper=1)`
* `kappa_dropout`: Nested prior for a and b priors; defaults to `Prior("Pareto", alpha=1, m=1)`
* `purchase_covariates`: Coefficients for purchase rate covariates; defaults to `Normal(0, 3)`
* `dropout_covariates`: Coefficients for dropout covariates; defaults to `Normal.dist(0, 3)`
* `purchase_covariate_cols`: List containing column names of covariates for customer purchase rates.
* `dropout_covariate_cols`: List containing column names of covariates for customer dropouts.
sampler_config : dict, optional
Expand Down Expand Up @@ -100,10 +100,10 @@
model = BetaGeoModel(
data=data,
model_config={
"r_prior": Prior("Weibull", alpha=2, beta=1),
"alpha_prior": Prior("HalfFlat"),
"a_prior": Prior("Beta", alpha=2, beta=3),
"b_prior": Prior("Beta", alpha=3, beta=2),
"r": Prior("Weibull", alpha=2, beta=1),
"alpha": Prior("HalfFlat"),
"a": Prior("Beta", alpha=2, beta=3),
"b": Prior("Beta", alpha=3, beta=2),
},
sampler_config={
"draws": 1000,
Expand Down Expand Up @@ -185,12 +185,12 @@
def default_model_config(self) -> ModelConfig:
"""Default model configuration."""
return {
"alpha_prior": Prior("Weibull", alpha=2, beta=10),
"r_prior": Prior("Weibull", alpha=2, beta=1),
"phi_dropout_prior": Prior("Uniform", lower=0, upper=1),
"kappa_dropout_prior": Prior("Pareto", alpha=1, m=1),
"purchase_coefficient_prior": Prior("Normal", mu=0, sigma=1),
"dropout_coefficient_prior": Prior("Normal", mu=0, sigma=1),
"alpha": Prior("Weibull", alpha=2, beta=10),
"r": Prior("Weibull", alpha=2, beta=1),
"phi_dropout": Prior("Uniform", lower=0, upper=1),
"kappa_dropout": Prior("Pareto", alpha=1, m=1),
"purchase_coefficient": Prior("Normal", mu=0, sigma=1),
"dropout_coefficient": Prior("Normal", mu=0, sigma=1),
"purchase_covariate_cols": [],
"dropout_covariate_cols": [],
}
Expand All @@ -211,16 +211,12 @@
self.data[self.purchase_covariate_cols],
dims=["customer_id", "purchase_covariate"],
)
self.model_config[
"purchase_coefficient_prior"
].dims = "purchase_covariate"
self.model_config["purchase_coefficient"].dims = "purchase_covariate"

Check warning on line 214 in pymc_marketing/clv/models/beta_geo.py

View check run for this annotation

Codecov / codecov/patch

pymc_marketing/clv/models/beta_geo.py#L214

Added line #L214 was not covered by tests
purchase_coefficient_alpha = self.model_config[
"purchase_coefficient_prior"
"purchase_coefficient"
].create_variable("purchase_coefficient_alpha")

alpha_scale = self.model_config["alpha_prior"].create_variable(
"alpha_scale"
)
alpha_scale = self.model_config["alpha"].create_variable("alpha_scale")

Check warning on line 219 in pymc_marketing/clv/models/beta_geo.py

View check run for this annotation

Codecov / codecov/patch

pymc_marketing/clv/models/beta_geo.py#L219

Added line #L219 was not covered by tests
alpha = pm.Deterministic(
"alpha",
(
Expand All @@ -232,29 +228,27 @@
dims="customer_id",
)
else:
alpha = self.model_config["alpha_prior"].create_variable("alpha")
alpha = self.model_config["alpha"].create_variable("alpha")

# dropout priors
if "a_prior" in self.model_config and "b_prior" in self.model_config:
if "a" in self.model_config and "b" in self.model_config:
if self.dropout_covariate_cols:
dropout_data = pm.Data(
"dropout_data",
self.data[self.dropout_covariate_cols],
dims=["customer_id", "dropout_covariate"],
)

self.model_config[
"dropout_coefficient_prior"
].dims = "dropout_covariate"
self.model_config["dropout_coefficient"].dims = "dropout_covariate"

Check warning on line 242 in pymc_marketing/clv/models/beta_geo.py

View check run for this annotation

Codecov / codecov/patch

pymc_marketing/clv/models/beta_geo.py#L242

Added line #L242 was not covered by tests
dropout_coefficient_a = self.model_config[
"dropout_coefficient_prior"
"dropout_coefficient"
].create_variable("dropout_coefficient_a")
dropout_coefficient_b = self.model_config[
"dropout_coefficient_prior"
"dropout_coefficient"
].create_variable("dropout_coefficient_b")

a_scale = self.model_config["a_prior"].create_variable("a_scale")
b_scale = self.model_config["b_prior"].create_variable("b_scale")
a_scale = self.model_config["a"].create_variable("a_scale")
b_scale = self.model_config["b"].create_variable("b_scale")

Check warning on line 251 in pymc_marketing/clv/models/beta_geo.py

View check run for this annotation

Codecov / codecov/patch

pymc_marketing/clv/models/beta_geo.py#L250-L251

Added lines #L250 - L251 were not covered by tests
a = pm.Deterministic(
"a",
a_scale
Expand All @@ -268,8 +262,8 @@
dims="customer_id",
)
else:
a = self.model_config["a_prior"].create_variable("a")
b = self.model_config["b_prior"].create_variable("b")
a = self.model_config["a"].create_variable("a")
b = self.model_config["b"].create_variable("b")
else:
# hierarchical pooling of dropout rate priors
if self.dropout_covariate_cols:
Expand All @@ -279,22 +273,20 @@
dims=["customer_id", "dropout_covariate"],
)

self.model_config[
"dropout_coefficient_prior"
].dims = "dropout_covariate"
self.model_config["dropout_coefficient"].dims = "dropout_covariate"

Check warning on line 276 in pymc_marketing/clv/models/beta_geo.py

View check run for this annotation

Codecov / codecov/patch

pymc_marketing/clv/models/beta_geo.py#L276

Added line #L276 was not covered by tests
dropout_coefficient_a = self.model_config[
"dropout_coefficient_prior"
"dropout_coefficient"
].create_variable("dropout_coefficient_a")
dropout_coefficient_b = self.model_config[
"dropout_coefficient_prior"
"dropout_coefficient"
].create_variable("dropout_coefficient_b")

phi_dropout = self.model_config[
"phi_dropout_prior"
].create_variable("phi_dropout")
kappa_dropout = self.model_config[
"kappa_dropout_prior"
].create_variable("kappa_dropout")
phi_dropout = self.model_config["phi_dropout"].create_variable(

Check warning on line 284 in pymc_marketing/clv/models/beta_geo.py

View check run for this annotation

Codecov / codecov/patch

pymc_marketing/clv/models/beta_geo.py#L284

Added line #L284 was not covered by tests
"phi_dropout"
)
kappa_dropout = self.model_config["kappa_dropout"].create_variable(

Check warning on line 287 in pymc_marketing/clv/models/beta_geo.py

View check run for this annotation

Codecov / codecov/patch

pymc_marketing/clv/models/beta_geo.py#L287

Added line #L287 was not covered by tests
"kappa_dropout"
)

a_scale = pm.Deterministic(
"a_scale",
Expand All @@ -319,18 +311,18 @@
)

else:
phi_dropout = self.model_config[
"phi_dropout_prior"
].create_variable("phi_dropout")
kappa_dropout = self.model_config[
"kappa_dropout_prior"
].create_variable("kappa_dropout")
phi_dropout = self.model_config["phi_dropout"].create_variable(
"phi_dropout"
)
kappa_dropout = self.model_config["kappa_dropout"].create_variable(
"kappa_dropout"
)

a = pm.Deterministic("a", phi_dropout * kappa_dropout)
b = pm.Deterministic("b", (1.0 - phi_dropout) * kappa_dropout)

# r remains unchanged with or without covariates
r = self.model_config["r_prior"].create_variable("r")
r = self.model_config["r"].create_variable("r")

BetaGeoNBD(
name="recency_frequency",
Expand Down
Loading