From 4f8eba8f90c47e2a2e9e935a2db18629aabf7ef6 Mon Sep 17 00:00:00 2001 From: CamDavidsonPilon Date: Thu, 7 Mar 2019 19:44:57 -0500 Subject: [PATCH 1/4] travis + pandas --- .travis.yml | 1 + lifetimes/version.py | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 1dc22424..b04c2f87 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,6 +25,7 @@ before_install: - ls install: - "pip install -r dev_requirements.txt" + - "pip install pandas==$PANDAS_VERSION" # command to run tests script: - py.test --cov lifetimes diff --git a/lifetimes/version.py b/lifetimes/version.py index abf4c582..2f52a6d4 100644 --- a/lifetimes/version.py +++ b/lifetimes/version.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- from __future__ import unicode_literals -__version__ = "0.11.0" +__version__ = "0.11.1" From 960446bed9e2d3f534bb1321369e108b9ee1e3c7 Mon Sep 17 00:00:00 2001 From: CamDavidsonPilon Date: Thu, 7 Mar 2019 19:53:18 -0500 Subject: [PATCH 2/4] allows pandas < 0.24 --- lifetimes/utils.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lifetimes/utils.py b/lifetimes/utils.py index 73476bd6..acd88382 100644 --- a/lifetimes/utils.py +++ b/lifetimes/utils.py @@ -123,7 +123,10 @@ def to_period(d): combined_data = calibration_summary_data.join(holdout_summary_data, how="left") combined_data.fillna(0, inplace=True) - delta_time = (to_period(observation_period_end) - to_period(calibration_period_end)).n + try: + delta_time = (to_period(observation_period_end) - to_period(calibration_period_end)).n + except AttributeError: + delta_time = to_period(observation_period_end) - to_period(calibration_period_end) combined_data["duration_holdout"] = delta_time return combined_data @@ -512,7 +515,10 @@ def expected_cumulative_transactions( first_trans_size = first_transactions.groupby(datetime_col).size() for i, period in enumerate(date_periods): if i % freq_multiplier == 0 and i > 0: - times = np.array([d.n for d in period - first_trans_size.index]) + try: + times = np.array([d.n for d in period - first_trans_size.index]) + except AttributeError: + times = period - first_trans_size.index times = times[times > 0].astype(float) / freq_multiplier expected_trans_agg = model.expected_number_of_purchases_up_to_time(times) From e628592971f897155b0323f963ed0e4558f59727 Mon Sep 17 00:00:00 2001 From: CamDavidsonPilon Date: Thu, 7 Mar 2019 21:21:39 -0500 Subject: [PATCH 3/4] bump version --- .travis.yml | 7 -- CHANGELOG.md | 4 ++ docs/Changelog.rst | 19 +++-- docs/conf.py | 70 +++++++++---------- lifetimes/fitters/__init__.py | 3 + .../fitters/beta_geo_beta_binom_fitter.py | 5 ++ lifetimes/fitters/beta_geo_fitter.py | 3 + lifetimes/fitters/gamma_gamma_fitter.py | 2 + lifetimes/fitters/modified_beta_geo_fitter.py | 3 + lifetimes/generate_data.py | 4 ++ lifetimes/utils.py | 11 +-- requirements.txt | 2 +- setup.py | 3 +- 13 files changed, 76 insertions(+), 60 deletions(-) diff --git a/.travis.yml b/.travis.yml index b04c2f87..69b7c1b3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,9 +6,6 @@ python: - "3.5" - "3.6" env: -- export PANDAS_VERSION=0.21.1 -- export PANDAS_VERSION=0.22.0 -- export PANDAS_VERSION=0.23.4 - export PANDAS_VERSION=0.24.1 # Enable newer 3.7 without globally enabling sudo and dist: xenial for other build jobs matrix: @@ -17,10 +14,6 @@ matrix: dist: xenial sudo: true env: export PANDAS_VERSION=0.24.1 - - python: 3.7 - dist: xenial - sudo: true - env: export PANDAS_VERSION=0.23.4 before_install: - ls install: diff --git a/CHANGELOG.md b/CHANGELOG.md index 0445a5be..5065a892 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +### 0.11.1 + - bump the Pandas requirements to >= 0.24.0. This should have been done in 0.11.0 + - suppress some warnings from autograd. + ### 0.11.0 - Move most models (all but Pareto) to autograd for automatic differentiation of their likelihood. This results in faster (at least 3x) and more successful convergence, plus allows for some really exciting extensions (coming soon). - `GammaGammaFitter`, `BetaGeoFitter`, `ModifiedBetaGeoFitter` and `BetaGeoBetaBinomFitter` have three new attributes: `confidence_interval_`, `variance_matrix_` and `standard_errors_` diff --git a/docs/Changelog.rst b/docs/Changelog.rst index fb3d5fa5..ad1fd7b4 100644 --- a/docs/Changelog.rst +++ b/docs/Changelog.rst @@ -1,6 +1,15 @@ Changelog ========= +0.11.1 +~~~~~~ + +- bump the Pandas requirements to >= 0.24.0. This should have been done + in 0.11.0 +- suppress some warnings from autograd. + +.. _section-1: + 0.11.0 ~~~~~~ @@ -20,7 +29,7 @@ Changelog - fixed a bug that was causing ``ParetoNBDFitter`` to generate data incorrectly. -.. _section-1: +.. _section-2: 0.10.1 ~~~~~~ @@ -38,7 +47,7 @@ Changelog - Stop support of scipy < 1.0. - Stop support of < Python 3.5. -.. _section-2: +.. _section-3: 0.10.0 ~~~~~~ @@ -57,7 +66,7 @@ Changelog used to reduce the size of the data (collapsing subjects with the same recency, frequency, T). -.. _section-3: +.. _section-4: 0.9.1 ~~~~~ @@ -74,7 +83,7 @@ Changelog difference in values compared to ``summary_from_transaction_data``. @DaniGate -.. _section-4: +.. _section-5: 0.9.0 ~~~~~ @@ -86,7 +95,7 @@ Changelog - Fixed a bug in ``expected_cumulative_transactions`` and ``plot_cumulative_transactions`` -.. _section-5: +.. _section-6: 0.8.1 ~~~~~ diff --git a/docs/conf.py b/docs/conf.py index 0405e716..ba8846d6 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -22,16 +22,17 @@ # sys.path.insert(0, os.path.abspath('.')) import sphinx_rtd_theme + html_theme = "sphinx_rtd_theme" html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] # Convert package README.md to intro.rst to include in index.rst for docs try: import pypandoc - long_description = pypandoc.convert_file('../README.md', 'rst', - outputfile='intro.rst') -except(ImportError): - print('Install pypandoc to convert README.md to intro.rst') + + long_description = pypandoc.convert_file("../README.md", "rst", outputfile="intro.rst") +except (ImportError): + print("Install pypandoc to convert README.md to intro.rst") # -- General configuration ------------------------------------------------ @@ -44,40 +45,38 @@ # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ - 'sphinx.ext.autodoc', - 'sphinx.ext.todo', - 'sphinx.ext.coverage', - 'sphinx.ext.mathjax', - 'sphinx.ext.napoleon' + "sphinx.ext.autodoc", + "sphinx.ext.todo", + "sphinx.ext.coverage", + "sphinx.ext.mathjax", + "sphinx.ext.napoleon", ] # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] # for parsing markdown files -source_parsers = { - '.md': 'recommonmark.parser.CommonMarkParser', -} +source_parsers = {".md": "recommonmark.parser.CommonMarkParser"} # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # -source_suffix = ['.rst', '.md'] +source_suffix = [".rst", ".md"] # The master toctree document. -master_doc = 'index' +master_doc = "index" # General information about the project. -project = 'lifetimes' -copyright = '2015, Cameron Davidson-Pilon' -author = 'Cameron Davidson-Pilon' +project = "lifetimes" +copyright = "2015, Cameron Davidson-Pilon" +author = "Cameron Davidson-Pilon" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. -version = '0.11.0' +version = "0.11.1" # The full version, including alpha/beta/rc tags. release = version @@ -91,10 +90,10 @@ # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This patterns also effect to html_static_path and html_extra_path -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' +pygments_style = "sphinx" # If true, `todo` and `todoList` produce output, else they produce nothing. todo_include_todos = True @@ -117,7 +116,7 @@ # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +html_static_path = ["_static"] # -- Napoleon settings ---------------------------------------------------- napoleon_google_docstring = True @@ -137,7 +136,7 @@ # -- Options for HTMLHelp output ------------------------------------------ # Output file base name for HTML help builder. -htmlhelp_basename = 'lifetimesdoc' +htmlhelp_basename = "lifetimesdoc" # -- Options for LaTeX output --------------------------------------------- @@ -146,15 +145,12 @@ # The paper size ('letterpaper' or 'a4paper'). # # 'papersize': 'letterpaper', - # The font size ('10pt', '11pt' or '12pt'). # # 'pointsize': '10pt', - # Additional stuff for the LaTeX preamble. # # 'preamble': '', - # Latex figure (float) alignment # # 'figure_align': 'htbp', @@ -163,20 +159,14 @@ # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). -latex_documents = [ - (master_doc, 'lifetimes.tex', 'lifetimes Documentation', - 'Cameron Davidson-Pilon', 'manual'), -] +latex_documents = [(master_doc, "lifetimes.tex", "lifetimes Documentation", "Cameron Davidson-Pilon", "manual")] # -- Options for manual page output --------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -man_pages = [ - (master_doc, 'lifetimes', 'lifetimes Documentation', - [author], 1) -] +man_pages = [(master_doc, "lifetimes", "lifetimes Documentation", [author], 1)] # -- Options for Texinfo output ------------------------------------------- @@ -185,7 +175,13 @@ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - (master_doc, 'lifetimes', 'lifetimes Documentation', - author, 'lifetimes', 'One line description of project.', - 'Miscellaneous'), + ( + master_doc, + "lifetimes", + "lifetimes Documentation", + author, + "lifetimes", + "One line description of project.", + "Miscellaneous", + ) ] diff --git a/lifetimes/fitters/__init__.py b/lifetimes/fitters/__init__.py index a63f7422..f294bafc 100644 --- a/lifetimes/fitters/__init__.py +++ b/lifetimes/fitters/__init__.py @@ -1,5 +1,8 @@ # -*- coding: utf-8 -*- """Base fitter for other classes.""" +import warnings + +warnings.simplefilter(action="ignore", category=FutureWarning) import dill import numpy as np import pandas as pd diff --git a/lifetimes/fitters/beta_geo_beta_binom_fitter.py b/lifetimes/fitters/beta_geo_beta_binom_fitter.py index c869a613..b4161b84 100644 --- a/lifetimes/fitters/beta_geo_beta_binom_fitter.py +++ b/lifetimes/fitters/beta_geo_beta_binom_fitter.py @@ -2,6 +2,9 @@ """Beta Geo Beta BinomFitter.""" from __future__ import division from __future__ import print_function +import warnings + +warnings.simplefilter(action="ignore", category=FutureWarning) import numpy as np import pandas as pd @@ -62,6 +65,8 @@ def __init__(self, penalizer_coef=0.0): @staticmethod def _loglikelihood(params, x, tx, T): + warnings.simplefilter(action="ignore", category=FutureWarning) + """Log likelihood for optimizer.""" alpha, beta, gamma, delta = params diff --git a/lifetimes/fitters/beta_geo_fitter.py b/lifetimes/fitters/beta_geo_fitter.py index 5ac4278b..0fd9cf0e 100644 --- a/lifetimes/fitters/beta_geo_fitter.py +++ b/lifetimes/fitters/beta_geo_fitter.py @@ -2,6 +2,7 @@ """Beta Geo Fitter, also known as BG/NBD model.""" from __future__ import print_function from __future__ import division +import warnings import pandas as pd import autograd.numpy as np @@ -146,6 +147,8 @@ def fit( @staticmethod def _negative_log_likelihood(log_params, freq, rec, T, weights, penalizer_coef): + warnings.simplefilter(action="ignore", category=FutureWarning) + params = np.exp(log_params) r, alpha, a, b = params diff --git a/lifetimes/fitters/gamma_gamma_fitter.py b/lifetimes/fitters/gamma_gamma_fitter.py index a401d1b2..43f5af21 100644 --- a/lifetimes/fitters/gamma_gamma_fitter.py +++ b/lifetimes/fitters/gamma_gamma_fitter.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- from __future__ import print_function from __future__ import division +import warnings import pandas as pd from autograd import numpy as np @@ -68,6 +69,7 @@ def __init__(self, penalizer_coef=0.0): @staticmethod def _negative_log_likelihood(log_params, frequency, avg_monetary_value, weights, penalizer_coef): + warnings.simplefilter(action="ignore", category=FutureWarning) params = np.exp(log_params) p, q, v = params diff --git a/lifetimes/fitters/modified_beta_geo_fitter.py b/lifetimes/fitters/modified_beta_geo_fitter.py index 0de0d20f..017eed51 100644 --- a/lifetimes/fitters/modified_beta_geo_fitter.py +++ b/lifetimes/fitters/modified_beta_geo_fitter.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- from __future__ import print_function from __future__ import division +import warnings import autograd.numpy as np from autograd.numpy import log, logaddexp @@ -113,6 +114,8 @@ def fit( @staticmethod def _negative_log_likelihood(log_params, freq, rec, T, weights, penalizer_coef): + warnings.simplefilter(action="ignore", category=FutureWarning) + params = np.exp(log_params) r, alpha, a, b = params diff --git a/lifetimes/generate_data.py b/lifetimes/generate_data.py index dc8d5f98..019470af 100644 --- a/lifetimes/generate_data.py +++ b/lifetimes/generate_data.py @@ -1,3 +1,7 @@ +# -*- coding: utf-8 -*- +import warnings + +warnings.simplefilter(action="ignore", category=FutureWarning) import numpy as np from numpy import random import pandas as pd diff --git a/lifetimes/utils.py b/lifetimes/utils.py index acd88382..a78eea7b 100644 --- a/lifetimes/utils.py +++ b/lifetimes/utils.py @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- """Lifetimes utils and helpers.""" from __future__ import division - import numpy as np import pandas as pd import dill @@ -123,10 +122,7 @@ def to_period(d): combined_data = calibration_summary_data.join(holdout_summary_data, how="left") combined_data.fillna(0, inplace=True) - try: - delta_time = (to_period(observation_period_end) - to_period(calibration_period_end)).n - except AttributeError: - delta_time = to_period(observation_period_end) - to_period(calibration_period_end) + delta_time = (to_period(observation_period_end) - to_period(calibration_period_end)).n combined_data["duration_holdout"] = delta_time return combined_data @@ -515,10 +511,7 @@ def expected_cumulative_transactions( first_trans_size = first_transactions.groupby(datetime_col).size() for i, period in enumerate(date_periods): if i % freq_multiplier == 0 and i > 0: - try: - times = np.array([d.n for d in period - first_trans_size.index]) - except AttributeError: - times = period - first_trans_size.index + times = np.array([d.n for d in period - first_trans_size.index]) times = times[times > 0].astype(float) / freq_multiplier expected_trans_agg = model.expected_number_of_purchases_up_to_time(times) diff --git a/requirements.txt b/requirements.txt index 7acb14af..1b1f3cd5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ numpy>1.10.0 scipy>=1.0.0 -pandas>=0.21.1 +pandas>=0.24.0 dill>=0.2.6 autograd>=1.2.0 diff --git a/setup.py b/setup.py index 32696e56..ecfbb99b 100644 --- a/setup.py +++ b/setup.py @@ -1,4 +1,5 @@ #!/usr/bin/env python +# -*- coding: utf-8 -*- import os from setuptools import setup @@ -32,7 +33,7 @@ "Programming Language :: Python :: 3.5", "Topic :: Scientific/Engineering", ], - install_requires=["numpy>=1.10.0", "scipy>=1.0.0", "pandas>=0.21.1", "autograd>=1.2.0", "dill>=0.2.6"], + install_requires=["numpy>=1.10.0", "scipy>=1.0.0", "pandas>=0.24.0", "autograd>=1.2.0", "dill>=0.2.6"], package_data={ "lifetimes": ["datasets/*", "../README.md", "../README.txt", "../LICENSE", "../MANIFEST.in", "fitters/*"] }, From 74c076bea90f9f9e5fd18265833e723ad9b97bc9 Mon Sep 17 00:00:00 2001 From: CamDavidsonPilon Date: Thu, 7 Mar 2019 21:32:08 -0500 Subject: [PATCH 4/4] docs --- docs/Quickstart.md | 9 +++++++++ docs/index.rst | 1 + lifetimes/utils.py | 1 - 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/docs/Quickstart.md b/docs/Quickstart.md index 4ef388ae..f8ababf2 100644 --- a/docs/Quickstart.md +++ b/docs/Quickstart.md @@ -41,6 +41,15 @@ print(bgf) """ """ + +bgf.summary +""" + coef se(coef) lower 95% bound upper 95% bound +r 0.242593 0.012557 0.217981 0.267205 +alpha 4.413532 0.378221 3.672218 5.154846 +a 0.792886 0.185719 0.428877 1.156895 +b 2.425752 0.705345 1.043276 3.808229 +""" ``` After fitting, we have lots of nice methods and properties attached to the fitter object, like ``param_`` and ``summary``. diff --git a/docs/index.rst b/docs/index.rst index 2413b37c..d2d4256c 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -12,6 +12,7 @@ Quickstart Saving and loading model More examples and recipes + lifetimes Changelog diff --git a/lifetimes/utils.py b/lifetimes/utils.py index a78eea7b..44424c33 100644 --- a/lifetimes/utils.py +++ b/lifetimes/utils.py @@ -10,7 +10,6 @@ __all__ = [ "calibration_and_holdout_data", "summary_data_from_transaction_data", - "_find_first_transactions", "calculate_alive_path", "expected_cumulative_transactions", ]