pymc-marketing icon indicating copy to clipboard operation
pymc-marketing copied to clipboard

Implementing Hill Saturation in PyMC-marketing

Open JakePiekarski314 opened this issue 1 year ago • 4 comments

Implements the Hill function, a sigmoidal model often used to describe saturation effects in various contexts, such as biochemical reactions, pharmacological dose-response relationships, and media spend efficiency in marketing. The function is characterized by a flexible sigmoidal curve that can model a range of response shapes from hyperbolic to S-shaped, depending on the parameters. The Hill function is given by: f(x) = 1 / (1 + (x / ec)^(-slope)) where: - x is the input variable representing the level of an independent factor (e.g., substrate concentration in biochemistry, dose in pharmacology, or media spend in marketing). - ec is the "half saturation point" or the "effective concentration" at which the function value is half of its maximum, indicating a point of inflection where the response starts to exhibit diminishing returns. - slope (often denoted as the Hill coefficient in biochemical contexts) is a dimensionless parameter that controls the steepness of the curve. It provides insight into the cooperativity or the intensity of the saturation effect: - slope < 1 indicates a more gradual increase (concave curve) leading to saturation, - slope = 1 represents a hyperbolic response similar to Michaelis-Menten kinetics in enzyme activity, - slope > 1 yields an S-shaped curve indicating a sharper transition between the phases of low and high response. Parameters: - x (float): Input variable (e.g., media spend, dose, substrate concentration) which the response depends on. - ec (float): Half saturation point, a critical value of 'x' where the response is half of its maximal value. It must be greater than 0 to avoid division by zero and ensure a meaningful inflection point. - slope (float): Shape control parameter that affects the curve's steepness and the responsiveness of the system to changes in 'x'. A positive value is required to maintain the sigmoidal nature of the function. Returns: - float: The output of the Hill function, representing the saturation effect or response level for the given input 'x'. The return value is bounded between 0 (as x approaches 0) and 1 (as x approaches infinity), representing the fraction of the maximal possible response. Example: - To model the effect of increasing media spend on the return on investment with diminishing returns beyond a certain point, one might use the Hill function with appropriate 'ec' and 'slope' values to capture the saturation effect.

Description

Related Issue

  • [ ] Closes #
  • [ ] Related to #

Checklist

Modules affected

  • [x] MMM
  • [ ] CLV

Type of change

  • [x] New feature / enhancement
  • [ ] Bug fix
  • [ ] Documentation
  • [ ] Maintenance
  • [ ] Other (please specify):

📚 Documentation preview 📚: https://pymc-marketing--606.org.readthedocs.build/en/606/

JakePiekarski314 avatar Mar 27 '24 17:03 JakePiekarski314

Hey @JakePiekarski314 great initiative! I think it's a good addition.

I have a few initial comments:

  1. Modify the style of the docstring to be numpy style.

  2. Even if the function came from biochemistry, we must related to marketing. Try to make the docstring more intuitive for marketers. Example, ec is located in which axis? What is controlling? What is their marketing concept?

  3. Remember the model is scaled, In case the value returned by the model is between 0 and 1, does the saturation occur at the maximum response of the target y? Or should this function be multiplied by the beta of the channel after? Could you provide an example of how you are using it in your models?

  4. Would be nice if you can add plots to the docstring. Check the other functions added already, should be something like:

"""
....
.. plot::
        :context: close-figs

        import numpy as np
        import matplotlib.pyplot as plt
        from pymc_marketing.mmm.transformers import hill_saturation

        x = np.linspace(0, 10, 100)

        # Varying sigma
        sigmas = [0.5, 1, 1.5]
        plt.figure(figsize=(12, 4))
        for i, sigma in enumerate(sigmas):
            plt.subplot(1, 3, i+1)
            y = hill_saturation(x, sigma, 2, 5)
            plt.plot(x, y)
            plt.xlabel('x')
            plt.ylabel('Hill Saturation')
            plt.title(f'Sigma = {sigma}')
        plt.tight_layout()
        plt.show()
"""

cetagostini avatar Mar 27 '24 21:03 cetagostini

PS: Make sure the pre-commit check are pass. You just need to run the following command in the terminal pre-commit run --all-files

cetagostini avatar Mar 27 '24 21:03 cetagostini

Codecov Report

Attention: Patch coverage is 50.00000% with 1 line in your changes missing coverage. Please review.

Project coverage is 91.53%. Comparing base (93f00de) to head (f316036). Report is 178 commits behind head on main.

Files with missing lines Patch % Lines
pymc_marketing/mmm/transformers.py 50.00% 1 Missing :warning:
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #606      +/-   ##
==========================================
- Coverage   91.57%   91.53%   -0.04%     
==========================================
  Files          21       21              
  Lines        2172     2174       +2     
==========================================
+ Hits         1989     1990       +1     
- Misses        183      184       +1     

:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.

codecov[bot] avatar Mar 28 '24 08:03 codecov[bot]

Hey @JakePiekarski314 Carlos and I have been working on a change to allow users to specify adstock and saturation in this PR: #632 Carlos also took a stab at the hill saturation function as well in the PR as well. It might be good to close this PR and consolidate there with the larger changes. Would you be able to give your feedback on the Hill saturation implementation?

williambdean avatar Apr 25 '24 14:04 williambdean

Hey team, given the new PR #632 I'll close this one!

cetagostini avatar Jun 11 '24 14:06 cetagostini

Thanks for starting this PR @JakePiekarski314 Give the new version a try and let us know what you think. If you have a take a prior defaults, please let us know as well.

williambdean avatar Jun 11 '24 16:06 williambdean