Skip to content
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

Add new customer_choice module #803

Merged
merged 268 commits into from
Dec 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
268 commits
Select commit Hold shift + click to select a range
78964f0
Update version.txt (#640)
juanitorduz Apr 19, 2024
18d926c
[pre-commit.ci] pre-commit autoupdate (#642)
pre-commit-ci[bot] Apr 23, 2024
ce41f5f
Fix build badge (#645)
juanitorduz Apr 23, 2024
818781a
Add downloads stats to README
juanitorduz Apr 25, 2024
91564cf
Pareto/NBD Example Notebook (#646)
ColtAllen Apr 25, 2024
7034e28
add spaces, increase indentation, and fix number order to Pareto note…
wd60622 Apr 27, 2024
d531d0c
Add link to new Pareto notebook (#649)
juanitorduz Apr 27, 2024
1c186f0
Plot Waterfall Components Decomposition (#631)
cetagostini-wise Apr 28, 2024
b36b0ac
Update resources.md (#652)
coreyabs-db Apr 29, 2024
ae6ae1d
fix ylabel (#654)
juanitorduz Apr 29, 2024
41dda4f
[pre-commit.ci] pre-commit autoupdate (#655)
pre-commit-ci[bot] Apr 29, 2024
a89bd93
Lift test fixes (#656)
wd60622 Apr 30, 2024
5a93ef2
add to docstrings tanh saturation (#657)
wd60622 Apr 30, 2024
b58f9b6
Add quickstart to readme (#653)
juanitorduz Apr 30, 2024
e63929a
Add contributors to README (#659)
juanitorduz May 1, 2024
f0097e2
Time varying intercept (#628)
ulfaslak May 1, 2024
8e67803
Update README.md (#660)
nialloulton May 1, 2024
fd6b331
Add tv intrecept to readme (#661)
juanitorduz May 2, 2024
b27da9e
fix title level (#663)
juanitorduz May 2, 2024
b785baa
Remove unnecessary NonImplemented errors from abstract methods (#662)
juanitorduz May 2, 2024
19bbf6d
Pass conv mode to adstock functions (#665)
juanitorduz May 2, 2024
fc37560
[Try] Fix compressed images in docs. (#667)
juanitorduz May 3, 2024
5f54d8e
Update pyproject.toml (#671)
juanitorduz May 5, 2024
0e8ac45
add license (#673)
juanitorduz May 5, 2024
48c88b2
use grep and sed in the env line (#675)
wd60622 May 6, 2024
2374a0c
add sample_kwargs (#676)
juanitorduz May 8, 2024
4dbf943
MMM NB Improvements (waterfall & error plots) (#664)
juanitorduz May 8, 2024
61da9c0
Update version.txt (#677)
juanitorduz May 8, 2024
6e37d3b
[pre-commit.ci] pre-commit autoupdate (#683)
pre-commit-ci[bot] May 13, 2024
ad2353a
v0 Streamlit MMM Explainer App (#614)
louismagowan May 21, 2024
9aa8bc0
Correct BetaGeo docstring example (#693)
wd60622 May 22, 2024
ae84163
Add `BetaGeoBetaBinom` Distribution Block (#431)
ColtAllen May 27, 2024
0e6ce83
[pre-commit.ci] pre-commit autoupdate (#705)
pre-commit-ci[bot] May 27, 2024
3feec18
Fix related to column renaming after aggregating test frequency (#698)
IvanUgrin May 28, 2024
b763c12
RFM Segmentation (#680)
ColtAllen May 28, 2024
7be19f6
create bgbb_donations.csv (#710)
ColtAllen Jun 2, 2024
b4d84cc
closes #678 (#716)
wd60622 Jun 3, 2024
ba41aef
use URL for README image (#715)
wd60622 Jun 3, 2024
86805a4
closes #264 (#714)
wd60622 Jun 3, 2024
6edc4ca
[pre-commit.ci] pre-commit autoupdate (#719)
pre-commit-ci[bot] Jun 3, 2024
f79b7b0
Update `BetaGeoModel` API (#709)
ColtAllen Jun 9, 2024
f3be754
User-defined media transformations and custom ordering (#632)
cetagostini-wise Jun 10, 2024
dc117be
CLV Plotting API (#728)
ColtAllen Jun 10, 2024
c31bee4
[pre-commit.ci] pre-commit autoupdate (#730)
pre-commit-ci[bot] Jun 10, 2024
46ba03f
Fix some ParetoNBDModel docstring typos (#731)
Mews Jun 11, 2024
b6a938f
pass kwargs to minimizer (#737)
juanitorduz Jun 12, 2024
5296f0f
Minor improvements [MMM] (#735)
juanitorduz Jun 12, 2024
271966b
Set upper bound pymc 5.16 (#725)
juanitorduz Jun 12, 2024
6fe03dc
Media transformation sampling & plotting methods (#734)
wd60622 Jun 12, 2024
664b5ca
improve tests mmm utils (#738)
juanitorduz Jun 12, 2024
a148e83
`model.fit` doesn't remove prior samples (#741)
wd60622 Jun 12, 2024
4b6607a
Hierarchical Model Configuration (#743)
wd60622 Jun 13, 2024
0144bd3
[pre-commit.ci] pre-commit autoupdate (#756)
pre-commit-ci[bot] Jun 17, 2024
c994210
MMM Component Notebook (#748)
wd60622 Jun 18, 2024
8596c8a
start addressing sphinx warnings and rendering issues (#750)
OriolAbril Jun 18, 2024
5caa61a
Allowing Hierarchical Non Centered Parametrization (#747)
cetagostini Jun 21, 2024
5ff29b1
fix np typing (#763)
juanitorduz Jun 21, 2024
405a5cf
add it back (#764)
juanitorduz Jun 21, 2024
9f84dc9
remove noqa from plots (#761)
juanitorduz Jun 21, 2024
897cf3d
Creating Time Base component for Media Contribution (#752)
cetagostini Jun 22, 2024
6a5934c
Run Ruff Notebooks (#773)
juanitorduz Jun 23, 2024
0bfca1a
[pre-commit.ci] pre-commit autoupdate (#779)
pre-commit-ci[bot] Jun 25, 2024
cec2cc2
`GammaGammaModel` API Improvements (#758)
ColtAllen Jun 27, 2024
f6a1a37
Deepcopy of posterior to allow second `fit` call (#790)
wd60622 Jun 28, 2024
fafe354
Add prior predictive example notebook (#787)
juanitorduz Jun 28, 2024
d5c3d1e
CLV Modeling Domains and Docstrings (#785)
ColtAllen Jun 28, 2024
a933b70
fix nb (#793)
juanitorduz Jun 28, 2024
576cf45
Run example notebooks CI (#791)
juanitorduz Jun 28, 2024
9892311
docs: Update model_builder.py to resolve warning in documentation bui…
c0d33ngr Jun 30, 2024
93f5e77
Time Varying Media Contribution Notebook (#778)
cetagostini Jul 1, 2024
24496a0
prepare release (#799)
juanitorduz Jul 1, 2024
2388c01
`Prior` class to represent distributions (#759)
wd60622 Jul 1, 2024
5cda250
[pre-commit.ci] pre-commit autoupdate (#801)
pre-commit-ci[bot] Jul 1, 2024
67f3a65
initial stab at some docs
drbenvincent Jul 3, 2024
0385418
register new module in a few places
drbenvincent Jul 4, 2024
3f19612
initial stab at how-to example notebook + code + API docs
drbenvincent Jul 4, 2024
7179904
Pull out seasonality as `YearlyFourier` and `MonthlyFourier` (#802)
wd60622 Jul 5, 2024
496eb76
Separate Weibull adstock into CDF & PDF (#810)
wd60622 Jul 5, 2024
9d4d04a
Add typing and package classifiers (#811)
wd60622 Jul 5, 2024
9b691a9
add imports to mmm module (#812)
wd60622 Jul 5, 2024
36f5a25
Friday progress on notebook example
drbenvincent Jul 5, 2024
03e9215
Save & load support for time varying parameters (#815)
wd60622 Jul 8, 2024
723887a
migrate to Data and non-mutable coords (#816)
wd60622 Jul 8, 2024
a6bbb0a
improve introduction page
drbenvincent Jul 8, 2024
dedb482
updates to model priors, plotting market shares, and more
drbenvincent Jul 8, 2024
7058483
Add in model maths for MV-ITS, saturated market assumption
drbenvincent Jul 8, 2024
a97e272
[pre-commit.ci] pre-commit autoupdate (#817)
pre-commit-ci[bot] Jul 8, 2024
8d49278
fix up / improve the model maths and description
drbenvincent Jul 8, 2024
d766722
PoC: Use Pydantic as data validator (#809)
juanitorduz Jul 9, 2024
c113e5b
fixes + describe covariance matrix + add section on unsaturated marke…
drbenvincent Jul 9, 2024
a2c8c87
update title of intro docs page
drbenvincent Jul 9, 2024
0a2d358
add admonition box
drbenvincent Jul 9, 2024
336b3c5
initial stab at modeling products individually
drbenvincent Jul 9, 2024
650cdfa
fix scenario 3 sampling & commentary + allow user to supply sampler_k…
drbenvincent Jul 9, 2024
05abba7
Date Validation and MMM Model Hamonization (Pydantic) (#824)
juanitorduz Jul 10, 2024
0293c3d
close to done on docs + code?
drbenvincent Jul 10, 2024
3b75adb
add tests
drbenvincent Jul 10, 2024
992c4bb
enlightenment in terms of unsaturated markets
drbenvincent Jul 10, 2024
24f3a21
extract data generation functions into module code
drbenvincent Jul 10, 2024
0fab236
remove old generate_data
drbenvincent Jul 10, 2024
5dbe9c7
constrained -> saturated. parameterize a test
drbenvincent Jul 10, 2024
8de62b6
turn generate_saturated_data into a test fixture
drbenvincent Jul 10, 2024
4c55b7e
split plot_causal_impact into plot_causal_impact_sales and plot_causa…
drbenvincent Jul 10, 2024
c93470a
execute notebook
drbenvincent Jul 10, 2024
36e7582
Merge branch 'main' into incrementality
drbenvincent Jul 10, 2024
ec639a4
revert an accidental change from a global find & replace
drbenvincent Jul 10, 2024
d235ff4
Remove warnings during tests (#823)
wd60622 Jul 11, 2024
717702a
Future-proof `prior_linearized` method call (#806)
shuvayan Jul 11, 2024
6049ae8
Create inverse_scaled_logistic_saturation and the corresponding class…
arthurmello Jul 18, 2024
6619076
fix (#842)
juanitorduz Jul 19, 2024
4cc4ba5
use labs theme as external (#830)
OriolAbril Jul 19, 2024
7a8b627
specify 0.9.0 as deprecation version (#849)
wd60622 Jul 22, 2024
a98815f
add intercept and target variable to example (#850)
wd60622 Jul 22, 2024
e6f844f
Various MMM small documentation fixes (#854)
juanitorduz Jul 22, 2024
8234c4b
Update UML diagrams (#856)
drbenvincent Jul 23, 2024
28ea158
Fixing ruff commands in Makefile #825 (#859)
MuradKhalil Jul 23, 2024
d759eb3
[pre-commit.ci] pre-commit autoupdate (#855)
pre-commit-ci[bot] Jul 24, 2024
b10f1f1
Fix model_builder docstrings (#861)
GiannisApost Jul 24, 2024
b7b97e7
add GH discussions link to README (#866)
cluhmann Jul 24, 2024
8ee9254
Skip coords with scalar value (#868)
GiannisApost Jul 25, 2024
9129a9e
Fix Visual for hill_saturation function (Issue #851 ) (#857)
PatrickRobotham Jul 25, 2024
de5679f
Allow plot MMM components in the original scale (#870)
juanitorduz Jul 25, 2024
19aea61
Inference changed to dataset (#873)
Ishaanjolly Jul 25, 2024
9755d3b
Add root saturation function (issue #702) (#858)
iraur Jul 25, 2024
7090401
Check for missing attrs after `sample_prior_predictive` and `fit` (#867)
wd60622 Jul 28, 2024
43131db
`json.loads` with python types bug (#881)
wd60622 Jul 29, 2024
24e9833
[pre-commit.ci] pre-commit autoupdate (#883)
pre-commit-ci[bot] Jul 29, 2024
7a89f27
Fix default `ConvMode` in docstring (#864)
ferrine Jul 29, 2024
ac645c9
Save off media transformations (#882)
wd60622 Jul 30, 2024
37cf3c8
Update deployment docs (#887)
wd60622 Jul 30, 2024
15396cd
Automate UML creation (#886)
wd60622 Jul 30, 2024
c72fb8a
prepare release (#888)
wd60622 Jul 30, 2024
4abac88
Update README.md (#893)
juanitorduz Jul 31, 2024
00d4e20
Add url health job from streamlit app (#902)
juanitorduz Aug 2, 2024
3eb5407
small improvements model config nb (#906)
juanitorduz Aug 2, 2024
dffae87
Add link model deployment to example notebook (#904)
juanitorduz Aug 2, 2024
41dd8a3
Add pymc-marketing version to some MMM notebooks (#907)
juanitorduz Aug 2, 2024
39f2336
Move adstock and saturation method imports to mmm.__all__ (#908)
PabloRoque Aug 5, 2024
ff4eef1
chore(Makefile): Adding a self-documenting command and light command …
louismagowan Aug 5, 2024
e3c79aa
Fix uml permissions (#913)
wd60622 Aug 5, 2024
6779fd1
[pre-commit.ci] pre-commit autoupdate (#914)
pre-commit-ci[bot] Aug 6, 2024
789aa0d
Don't run tests for non-code changes (#898)
dandeandean Aug 7, 2024
b070375
test running budget allocator nb (#919)
juanitorduz Aug 11, 2024
285f704
make hill pass through the origin (#920)
juanitorduz Aug 12, 2024
bfeb756
Add MMM ROAS Priors Case Study (#916)
juanitorduz Aug 12, 2024
1f89294
typo (#923)
juanitorduz Aug 12, 2024
1c8fefa
[pre-commit.ci] pre-commit autoupdate (#926)
pre-commit-ci[bot] Aug 12, 2024
49ac689
Original hill function definition (#925)
juanitorduz Aug 12, 2024
93fc9d9
MLflow autologging (#921)
wd60622 Aug 14, 2024
c1b5933
Adding BLAS to the env generation.
cetagostini Aug 14, 2024
35c8850
Merge branch 'main' of https://github.com/pymc-labs/pymc-marketing
cetagostini Aug 14, 2024
809a079
Solving optimizer issues & typos (#933)
cetagostini Aug 17, 2024
8d116b5
Log number of posterior & tuning samples (#943)
wd60622 Aug 18, 2024
5bbce01
point to GH discussions (#944)
cluhmann Aug 19, 2024
3126ae0
[pre-commit.ci] pre-commit autoupdate (#946)
pre-commit-ci[bot] Aug 19, 2024
a592824
fix typo
drbenvincent Aug 21, 2024
d20ecd9
fix admonition block + markdown heading level
drbenvincent Aug 21, 2024
4f9f349
collect results of plot funcs in tests
drbenvincent Aug 21, 2024
2be0344
add no cover comments
drbenvincent Aug 21, 2024
2cc2e3c
Merge branch 'main' into incrementality
drbenvincent Aug 21, 2024
a8dcc77
explicit module level scope for fixture
drbenvincent Aug 21, 2024
cbe217d
consistent use of product_incrementality for folder names
drbenvincent Aug 21, 2024
e798bba
background_sales -> existing_sales
drbenvincent Aug 21, 2024
63616af
innovation_sales -> treatment_sales
drbenvincent Aug 21, 2024
f6c6825
Fallback to defaults in `adstock|saturation_from_dict` (#955)
PabloRoque Aug 22, 2024
39d38b7
Add PyDocStyle Support (#951)
juanitorduz Aug 22, 2024
6e9992e
change to normal likelihood truncated at zero
drbenvincent Aug 22, 2024
6ada916
use empirical estimate for HalfNormal sigma for observation noise std
drbenvincent Aug 22, 2024
d3d0d5f
remove commented out lines
drbenvincent Aug 22, 2024
fab8a8d
use just one idata instance - removes idata_counterfactual
drbenvincent Aug 22, 2024
dce3f9e
Merge branch 'main' into incrementality
drbenvincent Aug 22, 2024
5e03f4b
make pre-commit checks pass
drbenvincent Aug 22, 2024
6f84f9b
break up code in __init__ into smaller methods
drbenvincent Aug 22, 2024
f452939
remove @property and deal with some consequences of that
drbenvincent Aug 22, 2024
255eac1
deprecate WeibullAdstock in favor of WeibullCDFAdstock and WeibullPDF…
wd60622 Aug 22, 2024
943a2c4
Raise informative error when including target in `X` (#962)
cluhmann Aug 22, 2024
1536dad
Ensure `fit` reproducibility (#963)
wd60622 Aug 22, 2024
b478d9d
Enforce `check_parameters` for `alpha` in `geometric_adstock` (#960)
PabloRoque Aug 22, 2024
bb8d063
scaling should be done before hdi computation (#970)
juanitorduz Aug 24, 2024
7d3b832
Fix UML permissions from forks / Run only on merge to main (#967)
wd60622 Aug 24, 2024
288b8e8
`DelayedSaturatedMMM` deprecations and moving files (#965)
wd60622 Aug 24, 2024
0c90ba8
Register and allow custom transform for `Prior` class (#972)
wd60622 Aug 25, 2024
cc89b95
Update pypi.yml (#975)
juanitorduz Aug 26, 2024
16b10ba
[pre-commit.ci] pre-commit autoupdate (#977)
pre-commit-ci[bot] Aug 26, 2024
28b75c3
Added deprecation warning for method keyword (#974)
radiokosmos Aug 26, 2024
6c46d59
Improve and sync the README and landing page. (#978)
juanitorduz Aug 28, 2024
cafa3f8
Time slice cross validation MMM Notebook (#971)
juanitorduz Aug 29, 2024
3048a74
fix the wrong trigger (#983)
wd60622 Aug 29, 2024
f2318ae
Media transformation class and different transformations based on sub…
wd60622 Aug 29, 2024
2e2907a
Changed pt=pt to pt_lib = None to avoid showing full module path in d…
radiokosmos Sep 1, 2024
f1e86c9
Linear trend (#991)
wd60622 Sep 2, 2024
ac2cbc2
Merge branch 'main' into incrementality
drbenvincent Sep 2, 2024
b712be0
Merge branch 'main' into incrementality
wd60622 Oct 22, 2024
cd72cad
revert link
wd60622 Oct 22, 2024
a0f0d67
add item for new module
wd60622 Oct 22, 2024
ef82c07
Use ModelBuilder for incrementality model (#1101)
wd60622 Oct 23, 2024
a958c86
add informed prior method
wd60622 Oct 23, 2024
67c984b
begin to modify the existing notebooks
wd60622 Oct 23, 2024
ad11612
Merge branch 'main' into incrementality
wd60622 Oct 23, 2024
075053a
add y to the mix
wd60622 Oct 24, 2024
4c1d4aa
changes to saturated notebook
wd60622 Oct 24, 2024
7e90da2
run with the accept kwargs
wd60622 Oct 24, 2024
c865183
rename product_incrementality module to cc
drbenvincent Oct 25, 2024
b1c5eb6
Merge branch 'main' into incrementality
drbenvincent Oct 25, 2024
930bf34
fix typo
drbenvincent Oct 25, 2024
c63ffd7
add a placeholder quickstart docs page
drbenvincent Oct 25, 2024
2e11fa8
rename a folder (previously missed) product_incrementality -> cc
drbenvincent Oct 25, 2024
6217c24
more instances of product incrementality -> customer choice
drbenvincent Oct 25, 2024
c96a568
market_saturated -> saturated_market
drbenvincent Oct 25, 2024
e6b37b5
add quickstart/cc/index to the getting_started page
drbenvincent Oct 25, 2024
a4a8891
avoid reusing `result` for multiple different scenarios
drbenvincent Oct 25, 2024
853f20a
notation change: rename "background" to "existing"
drbenvincent Oct 25, 2024
704fc25
add kwarg plot_total_sales to plot functions
drbenvincent Oct 25, 2024
f935572
Merge branch 'main' into incrementality
drbenvincent Oct 28, 2024
6eeec0e
rename module cc -> customer_choice
drbenvincent Oct 29, 2024
c8bb62b
remove type hint on plot_total_sales to make tests pass
drbenvincent Oct 29, 2024
da0b6a1
Merge branch 'main' into incrementality
drbenvincent Oct 29, 2024
1c02931
get docs to build / pass tests
drbenvincent Oct 29, 2024
183de56
finish the customer_choice getting started page
drbenvincent Oct 29, 2024
34ebd06
fix typo
drbenvincent Oct 29, 2024
ecc08c9
remove manual tight_layout commands
drbenvincent Oct 29, 2024
574fb41
fix typo
drbenvincent Oct 29, 2024
0a62d2b
grammatical fix
drbenvincent Oct 29, 2024
b72223f
fix typo
drbenvincent Oct 29, 2024
6a3529a
surpress a plot output
drbenvincent Oct 29, 2024
e6d79ed
fix typo
drbenvincent Oct 29, 2024
17b2d1f
update imports + split data generation code into different .py file
drbenvincent Oct 30, 2024
d47a1f9
Merge branch 'main' into incrementality
drbenvincent Oct 30, 2024
558e43f
fix imports in tests
drbenvincent Oct 31, 2024
f5e7040
Merge branch 'main' into incrementality
wd60622 Oct 31, 2024
9f79322
add docstrings to synthetic data module
wd60622 Oct 31, 2024
4d95503
switch rng parameter to random_seed
wd60622 Oct 31, 2024
0a28168
import from the customer_choice over submodule
wd60622 Oct 31, 2024
f3924a7
add docstrings to the model and plot function and mypy
wd60622 Oct 31, 2024
1586ca8
add file autolabeling
wd60622 Oct 31, 2024
bb1ec6f
allow for ax argument
wd60622 Oct 31, 2024
cd11a9e
fix the test seed name
wd60622 Oct 31, 2024
d8d6105
change import
wd60622 Oct 31, 2024
f081993
increase tests / find some holes
wd60622 Nov 1, 2024
a0b3858
use random_seed instead of rng
wd60622 Nov 1, 2024
e64626f
Merge branch 'main' into incrementality
wd60622 Nov 3, 2024
2a67bc9
Merge branch 'main' into incrementality
drbenvincent Nov 19, 2024
8c6dfc9
Merge branch 'main' into incrementality
wd60622 Dec 13, 2024
c52881f
fix conflicts
juanitorduz Dec 22, 2024
c4908f1
Merge branch 'main' into incrementality
juanitorduz Dec 22, 2024
9b64548
lint
juanitorduz Dec 22, 2024
886e2f8
Merge branch 'main' into incrementality
juanitorduz Dec 22, 2024
3472013
Merge branch 'main' into incrementality
juanitorduz Dec 27, 2024
135a070
Merge branch 'main' into incrementality
juanitorduz Dec 28, 2024
bff4ed0
Merge branch 'main' into incrementality
juanitorduz Dec 28, 2024
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
6 changes: 6 additions & 0 deletions .github/labeler.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ CLV:
- docs/source/notebooks/clv/*
- pymc_marketing/clv/**

"customer choice":
- changed-files:
- any-glob-to-any-file:
- docs/source/notebooks/customer_choice/*
- pymc_marketing/customer_choice/**

"Prior class":
- changed-files:
- any-glob-to-any-file:
Expand Down
1 change: 1 addition & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
<!--- Please list the modules that are affected by this PR by typing an `x` in the boxes below: -->
- [ ] MMM
- [ ] CLV
- [ ] Customer Choice
<!--- Additionally, if you are a maintainer or reviewer, please make sure that the appropriate labels are added to this PR -->

## Type of change
Expand Down
10 changes: 10 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,16 @@ Classes

![](docs/source/uml/classes_clv.png)

## Overview of the customer choice codebase

Packages

![](docs/source/uml/packages_customer_choice.png)

Classes

![](docs/source/uml/classes_customer_choice.png)

---

This guide takes some inspiration from the [Bambi guide to contributing](https://github.com/bambinos/bambi/blob/main/CONTRIBUTING.md)
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ uml: ## Install documentation dependencies and generate UML diagrams
pip install .[docs]
pyreverse pymc_marketing/mmm -d docs/source/uml -f 'ALL' -o png -p mmm
pyreverse pymc_marketing/clv -d docs/source/uml -f 'ALL' -o png -p clv
pyreverse pymc_marketing/customer_choice -d docs/source/uml -f 'ALL' -o png -p customer_choice

mlflow_server: ## Start MLflow server on port 5000
mlflow server --backend-store-uri sqlite:///mlruns.db --default-artifact-root ./mlruns
Expand Down
1 change: 1 addition & 0 deletions docs/source/api/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
model_config
model_builder
prior
customer_choice
metrics
mlflow
deserialize
Expand Down
1 change: 1 addition & 0 deletions docs/source/getting_started/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ installation/index

quickstart/clv/index
quickstart/mmm/index
quickstart/customer_choice/index
:::
41 changes: 41 additions & 0 deletions docs/source/getting_started/quickstart/customer_choice/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Customer Choice Quickstart

```python
from pymc_marketing.customer_choice import (
MVITS,
generate_saturated_data,
plot_product,
)

# Generate simulated data
scenario = {
"total_sales_mu": 1000,
"total_sales_sigma": 5,
"treatment_time": 40,
"n_observations": 100,
"market_shares_before": [[0.7, 0.3, 0]],
"market_shares_after": [[0.65, 0.25, 0.1]],
"market_share_labels": ["competitor", "own", "new"],
"random_seed": rng,
}

data = generate_saturated_data(**scenario)

# Build a multivariate interrupted time series model
model = MVITS(
existing_sales=["competitor", "own"],
saturated_market=True,
)

model.inform_default_prior(
data=data.loc[: scenario1["treatment_time"], ["competitor", "own"]]
)

# Parameter estimation
model.sample(data[["competitor", "own"]], data["new"])

# Visualize the results
model.plot_fit();
```

See the {ref}`howto` section for more information about using the customer choice module.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/source/guide/customer_choice/inc_simple.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
40 changes: 40 additions & 0 deletions docs/source/guide/customer_choice/incrementality_intro.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Introduction to causal product incrementality analysis

Let's say your company sells many products into a busy market with many competitors. Over time, both you and your competitors have been releasing new products and discontinuing old ones. Your goal, depending on your company’s strategy, might be to increase market share, sales volume, or profit margins.

One way this is typically done is by releasing new products that you believe will appeal to customers more than your competitors’ products. But how do you know if your new products are successful? If your new product sells, those sales could be coming from a variety of sources:
* **Market growth**: These are sales that come from new customers entering the market. This would be a desirable outcome.
* **Incremental sales**: These are sales that come from customers who would have bought a competitor’s product if you hadn’t released your new product. This is also a good outcome.
* **Cannibalistic sales**: These sales have come from customers who would have bought one of your existing products if you hadn’t released your new product. So while the new product's sales are non-zero, they are cannibalizing sales from your existing products.

So we can imagine a busy marketplace of products, where each product has a certain number of sales. We also have many new products being released and old products being discontinued.

In an effort to understand where sales are coming from we may have purchased retail sales data which gives us time series data on the sales of all products in the market. But how can we use this data to understand where our sales are coming from?

If we can do this, then we could gain valuable insights that could inform our company’s product portfolio decisions. For example, we could:
* Understand which products are driving market growth
* Understand which products are incremental, taking sales from competitors
* Understand which products are cannibalizing sales from other products

We might be tempted to think of cannibalistic sales as 'bad'. But this need not be the case, it depends entirely on your product strategy. For example, it could be that you want to constantly improve your product line up, releasing products with better attributes which are superior to competitors. In this case, you would expect sales of older products to decrease as customers switch to the new products. This can be a desirable outcome.

## Causal inference in product incrementality

Let's develop the basic logic behind a causal understanding of product incrementality. We will use a simple example to illustrate the key concepts.

In the plot below we have a period of time before we release a new product. We can see that sales of products A, B, and C are stable (yes this is a simplification!). But half way through our time period we release a new product and we can see that it sells reasonable volumes. The question is, where are these sales coming from?
![](inc_simple.png)

In this simplified example we could look at how the sales of existing products change, and infer where the sales of the new products came from. In this case we can see that the sales of product A and C have decreased (right at the time of the new product introduction) and so we could reasonably claim that the sales of the new product are cannibalizing sales from products A and C.

To be more precise, we aren't really able to make this causal inference based on the sales data _before_ new product introduction. Instead, we do it by comparing the actual product sales after the new product introduction to a counterfactual scenario where the new product was not introduced. This is the essence of causal inference in product incrementality. The question is how do we calculate the counterfactual sales?

![](inc_counterfactual.png)

In the trivially simple example above where sales are highly stable over time, we can do this with simple visual extrapolation. But in the real world, sales data will be noisy, exhibit seasonality, perhaps with some underlying trend, changes in prices, and marketing campaigns by you and your competitors and so on.

In fact, in many markets it is likely even more complex. We might not be able to neatly isolate time periods around new product introductions. We might have multiple new products being introduced at the same (or nearly the same) time.

![](inc_complex.png)

All of this added complexity will make it non-trivial to infer the causal impact of new products on existing products. The complexity of the product environment will need to be matched by a causal modeling strategy that can handle this complexity.
138 changes: 138 additions & 0 deletions docs/source/guide/customer_choice/mv_its_intro.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
# Multivariate interrupted time series models

One modeling approach we could use for causal analysis of product incrementality is the multivariate interrupted time series (MV-ITS) model. This model is a generalization of the interrupted time series model (ITS), which is a common approach in causal inference. The MV-ITS model allows us to estimate the causal impact of an intervention (e.g., a new product introduction) on multiple outcomes (e.g., sales of multiple products) simultaneously.

One of the differences between this model and the standard ITS modeling approach is that rather than having a binary off/on intervention, the time series of sales of the new product can be thought of as a graded intervention.

## Building our intuition

Below we outline the simplest possible version of the model to build up our intuition before we move on to more complex versions.

![](mv_its_schematic.jpg)

In this example we aggregate sales data into your companies total sales and your competitors total sales. We then have a time series of sales data for your company and your competitors. We can see that when we release a new product, our sales are not really affected, but our competitors' total sales decrease. So an intuitively right answer here is that our new product has a high level of incrementality.

```{admonition} The MV-ITS approach
:class: note
The MV-ITS approach models works as follows:
* It models the time series of sales data for your company and your competitors.
* These sales are modeled as normally distributed around an expected value with some degree of observation noise.
* The model expectation could be built up of multiple components, such as a trend, seasonality, and the impact of marketing campaigns. However for this simple example we have an intercept only model.
* Importantly, the expectation described above is decreased by some fraction of the new product sales. This fraction (across multiple sales outcomes) determines where the sales of the new product are coming from. From this, we can work out the level of incrementality of the new product.
```

## The simplest saturated market model

Let's start with the simplest case:
* The model description below assumes a saturated market. That is, new product sales have to be taken from existing sales and there is no growth of the overal size of the market.
* We operate on aggregated sales data in that we have total sales for all your products and all your competitors products. We also have all the sales data for the new product that you released.

We'll start by defining the model likelihood terms:

$$
\begin{aligned}
\vec{sales}_{your} \sim & \mathrm{Normal}(\gamma_{your} - c \cdot \vec{sales}_{new}, \sigma_{your})\\
\vec{sales}_{comp} \sim & \mathrm{Normal}(\gamma_{comp} - (1-c) \cdot \vec{sales}_{new}, \sigma_{comp})
\end{aligned}
$$

where $\vec{sales}_{your}$, $\vec{sales}_{comp}$, and $\vec{sales}_{new}$ are the observed time series of sales of all your products, your competitors products, and your new product, respectively.

The parameter $c \in [0, 1]$ is the proportion of new product sales that are cannibalistic, that is, have been taken from your existing products. Then $1-c$ is the proportion of new product sales that are incremental, that is, have been taken from your competitors products. We can place a Beta prior on $c$ to reflect our prior beliefs about the level of incrementality of the new product for example

The parameters $\sigma_{your}$ and $\sigma_{comp}$ are the standard deviations of the observation noise for your sales and your competitors sales, respectively. We can also place priors on these parameters to reflect our prior beliefs about the level of noise in the data.

This leaves the terms $\gamma_{your}$ and $\gamma_{comp}$, which are terms that model the sales of your products and your competitors products in the absence of the new product (which from a causal perspective we could also call the 'intervention'). One way to think about this would be to construct a model for sales prior to the new product release. This could be a simple model with an intercept term, or a more complex model with trend and seasonality terms. Right now we will just use an intercept term to keep things simple in this first model. In this case $\gamma_{your}$ and $\gamma_{comp}$ are simply parameters, intercept terms for your sales and your competitors sales, respectively. Again, we can place priors on these parameters to reflect our prior beliefs about the level of sales in the absence of the new product, but the exact form is not crucial at this point.

## Modelling products
We could relax one of the simplifications - rather than model aggregated sales for your or your competitors products, we could model sales for each product individually. This would allow us to see which products are most affected by the new product release. We could write the new likelihood terms as:

$$
\begin{aligned}
\vec{sales}_1 \sim & \mathrm{Normal}(\gamma_1 - \beta_1 \cdot \vec{sales}_{new}, \sigma_1)\\
\vec{sales}_2 \sim & \mathrm{Normal}(\gamma_2 - \beta_2 \cdot \vec{sales}_{new}, \sigma_2)\\
\vdots \\
\vec{sales}_P \sim & \mathrm{Normal}(\gamma_P - \beta_P \cdot \vec{sales}_{new}, \sigma_P)
\end{aligned}
$$

So now we have products $p=1, \ldots, P$ and we could model the sales of each product individually. We now have a new parameter $\beta_i$ for each product, which is the proportion of new product sales that are cannibalistic for that product. This allows us to see which products are most affected by the new product release. Because we have the assumption that the market is saturated, we can see that the sum of the $\beta_i$'s should equal 1. So it might be natural to place a [Dirichlet](https://en.wikipedia.org/wiki/Dirichlet_distribution) prior on the $\beta_i$'s:

$$
\beta_1, \beta_2, \ldots, \beta_P \sim \mathrm{Dirichlet}(\alpha_1, \ldots, \alpha_P)
$$

where all the $\alpha$ hyperparameters could be 1, for example.

As long as we have a list of which products are your products and which are your competitors products, we can simply sum the approriate $\beta_i$'s to get the cannibalistic and incremental sales for your products and your competitors products.

```{admonition} The multivariate normal form
:class: note
Note that you could re-write this model equivalently as:

$$
\begin{bmatrix}
\vec{sales}_1 \\
\vec{sales}_2 \\
\vdots \\
\vec{sales}_P
\end{bmatrix}
\sim \mathrm{MultivariateNormal}\left(
\begin{bmatrix}
\gamma_{1} - \beta_1 \cdot \vec{sales}_{new} \\
\gamma_{2} - \beta_2 \cdot \vec{sales}_{new} \\
\vdots \\
\gamma_{P} - \beta_P \cdot \vec{sales}_{new}
\end{bmatrix},
\Sigma
\right)
$$

We can embody the assumption that all the product sales are independent of each other by setting the off-diagonal elements of the covariance matrix $\Sigma$ to zero. The diagonal elements of the covariance matrix are the variances of the observation noise for each product $[ \sigma_1, \sigma_2 \ldots, \sigma_P ]$.
So the covariance matrix would look like:

$$
\Sigma =
\begin{pmatrix}
\sigma_{1}^2 & 0 & \cdots & 0 \\
0 & \sigma_{2}^2 & \cdots & 0 \\
\vdots & \vdots & \ddots & \vdots \\
0 & 0 & \cdots & \sigma_{P}^2
\end{pmatrix}
$$
```

## Relaxing independence assumptions
We could relax the assumption that the sales of your products and your competitors products are independent. We could model the sales of your products and your competitors products as a multivariate normal distribution (see box above).

The key difference would be to additionally estimate the off-diagnal elements of the covariance matrix. This would allow us to model the correlation between the sales of all products. This might require us to put more work in to specifying the prior on the covariance matrix, but in some situations the benefits of this approach could be worth it. The covariance matrix would now look like:

$$
\Sigma =
\begin{pmatrix}
\sigma_{11}^2 & \sigma_{12} & \cdots & \sigma_{1P} \\
\sigma_{21} & \sigma_{22}^2 & \cdots & \sigma_{2P} \\
\vdots & \vdots & \ddots & \vdots \\
\sigma_{P1} & \sigma_{P2} & \cdots & \sigma_{PP}^2
\end{pmatrix}
$$

The disadvantage of this model is that we would have a lot of parameters to estimate. For example, if there are $P$ products then we could have to estimate $P$ $\beta_i$'s and $P$ standard deviations and $P(P-1)/2$ covariances. This need not be a problem - we could place hierarchical priors on the $\beta_i$'s and the standard deviations for example, but it could be problematic with the covariances if we have a large number of products.

## Moving to an unsaturated market

Thus far we have considered the market as saturated. That is, it is assumed that the total sales of existing products are reduced by the same amount as the sales of the new product.

We could relax this assumption and consider an unsaturated market. More specifically, we could model the reduction of sales of existing products is less than the sales of the new product. Putting that another way, introduction of a new product leads to a reduction in existing product sales _but_ there are _additional_ sales of the new product which do not come from a reduction in the sales of existing products.

This requires only a minor change to the multivariate normal form of the model.

Specifically, rather than having $P$ products which are the source of new product sales, we could simply add a psuedo-product which represents new sales. The first $P$ products are as normal, all the existing products. The final pseudo product would represent the market growth. We could simply add an additional $\beta$ parameter and specify the prior as:

$$
\beta_1, \beta_2, \ldots, \beta_P, \beta_{P+1} \sim \mathrm{Dirichlet}(\alpha_1, \ldots, \alpha_P, \alpha_{P+1})
$$

The rest of the model remains unchanged.

Previously the sum of the $\beta$ parameters would be 1, which means that all new product sales are taken from existing products. Now the sum of the $\beta$ parameters relating to existing products ($\beta_1, \beta_2, \ldots, \beta_P$) could be less than 1. When $\beta_{P+1}>0$ then it means that the new product has caused the market to grow - some of the new product sales not come from reductions in sales of existing products.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions docs/source/guide/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,11 @@ mmm/resources

clv/clv_intro
:::

:::{toctree}
:caption: Customer Choice
:maxdepth: 1

customer_choice/incrementality_intro
customer_choice/mv_its_intro
:::
Loading
Loading