diff --git a/benchmarks/benchmarks/benchmarks.py b/benchmarks/benchmarks/benchmarks.py index bbf8fbd5fc3..489befbefc0 100644 --- a/benchmarks/benchmarks/benchmarks.py +++ b/benchmarks/benchmarks/benchmarks.py @@ -11,10 +11,10 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - import time import timeit +import arviz as az import numpy as np import pandas as pd import theano @@ -192,7 +192,7 @@ def track_glm_hierarchical_ess(self, init): compute_convergence_checks=False, ) tot = time.time() - t0 - ess = float(pm.ess(trace, var_names=["mu_a"])["mu_a"].values) + ess = float(az.ess(trace, var_names=["mu_a"])["mu_a"].values) return ess / tot def track_marginal_mixture_model_ess(self, init): @@ -214,7 +214,7 @@ def track_marginal_mixture_model_ess(self, init): compute_convergence_checks=False, ) tot = time.time() - t0 - ess = pm.ess(trace, var_names=["mu"])["mu"].values.min() # worst case + ess = az.ess(trace, var_names=["mu"])["mu"].values.min() # worst case return ess / tot @@ -245,7 +245,7 @@ def track_glm_hierarchical_ess(self, step): compute_convergence_checks=False, ) tot = time.time() - t0 - ess = float(pm.ess(trace, var_names=["mu_a"])["mu_a"].values) + ess = float(az.ess(trace, var_names=["mu_a"])["mu_a"].values) return ess / tot @@ -304,7 +304,7 @@ def freefall(y, t, p): t0 = time.time() trace = pm.sample(500, tune=1000, chains=2, cores=2, random_seed=0) tot = time.time() - t0 - ess = pm.ess(trace) + ess = az.ess(trace) return np.mean([ess.sigma, ess.gamma]) / tot diff --git a/docs/source/api.rst b/docs/source/api.rst index 4c15139f919..50b20c8f059 100644 --- a/docs/source/api.rst +++ b/docs/source/api.rst @@ -28,7 +28,6 @@ API Reference api/shape_utils api/ode - Indices and tables =================== diff --git a/docs/source/api/plots.rst b/docs/source/api/plots.rst index 70cf8719d28..0dec109b7f1 100644 --- a/docs/source/api/plots.rst +++ b/docs/source/api/plots.rst @@ -8,16 +8,7 @@ Plots are delegated to the `ArviZ `_. library, a general purpose library for "exploratory analysis of Bayesian models." -For plots, ``pymc3.`` are now aliases -for ArviZ functions. Thus, the links below will redirect you to -ArviZ docs: +Refer to its documentation to use the plotting functions directly. -- :func:`pymc3.traceplot ` -- :func:`pymc3.plot_posterior ` -- :func:`pymc3.forestplot ` -- :func:`pymc3.compareplot ` -- :func:`pymc3.autocorrplot ` -- :func:`pymc3.energyplot ` -- :func:`pymc3.kdeplot ` -- :func:`pymc3.densityplot ` -- :func:`pymc3.pairplot ` +.. automodule:: pymc3.plots.posteriorplot + :members: diff --git a/docs/source/api/stats.rst b/docs/source/api/stats.rst index 8d47e1adac1..bf85bb596dc 100644 --- a/docs/source/api/stats.rst +++ b/docs/source/api/stats.rst @@ -5,21 +5,4 @@ Statistics and diagnostics are delegated to the `ArviZ `_. library, a general purpose library for "exploratory analysis of Bayesian models." -For statistics and diagnostics, ``pymc3.`` are now aliases -for ArviZ functions. Thus, the links below will redirect you to -ArviZ docs: - -.. currentmodule:: pymc3.stats - - -- :func:`pymc3.bfmi ` -- :func:`pymc3.compare ` -- :func:`pymc3.ess ` -- :data:`pymc3.geweke ` -- :func:`pymc3.hpd ` -- :func:`pymc3.loo ` -- :func:`pymc3.mcse ` -- :func:`pymc3.r2_score ` -- :func:`pymc3.rhat ` -- :func:`pymc3.summary ` -- :func:`pymc3.waic ` +Refer to its documentation to use the diagnostics functions directly. diff --git a/pymc3/__init__.py b/pymc3/__init__.py index 23751b518ff..c42850ecf82 100644 --- a/pymc3/__init__.py +++ b/pymc3/__init__.py @@ -61,7 +61,6 @@ def __set_compiler_flags(): from pymc3.plots import * from pymc3.sampling import * from pymc3.smc import * -from pymc3.stats import * from pymc3.step_methods import * from pymc3.tests import test from pymc3.theanof import * diff --git a/pymc3/plots/__init__.py b/pymc3/plots/__init__.py index 15553e4570c..5923114cee3 100644 --- a/pymc3/plots/__init__.py +++ b/pymc3/plots/__init__.py @@ -14,9 +14,10 @@ """PyMC3 Plotting. -Plots are delegated to the ArviZ library, a general purpose library for -"exploratory analysis of Bayesian models." See https://arviz-devs.github.io/arviz/ -for details on plots. +Plots are delegated to the `ArviZ `_ library, a general purpose library for +exploratory analysis of Bayesian models. For more details, see https://arviz-devs.github.io/arviz/. + +Only `plot_posterior_predictive_glm` is kept in the PyMC code base for now, but it will move to ArviZ once the latter adds features for regression plots. """ import functools import sys @@ -24,98 +25,6 @@ import arviz as az - -def map_args(func): - swaps = [("varnames", "var_names")] - - @functools.wraps(func) - def wrapped(*args, **kwargs): - for (old, new) in swaps: - if old in kwargs and new not in kwargs: - warnings.warn( - f"Keyword argument `{old}` renamed to `{new}`, and will be removed in pymc3 3.8" - ) - kwargs[new] = kwargs.pop(old) - return func(*args, **kwargs) - - return wrapped - - -# pymc3 custom plots: override these names for custom behavior -autocorrplot = map_args(az.plot_autocorr) -forestplot = map_args(az.plot_forest) -kdeplot = map_args(az.plot_kde) -plot_posterior = map_args(az.plot_posterior) -energyplot = map_args(az.plot_energy) -densityplot = map_args(az.plot_density) -pairplot = map_args(az.plot_pair) - -# Use compact traceplot by default -@map_args -@functools.wraps(az.plot_trace) -def traceplot(*args, **kwargs): - try: - kwargs.setdefault("compact", True) - return az.plot_trace(*args, **kwargs) - except TypeError: - kwargs.pop("compact") - return az.plot_trace(*args, **kwargs) - - -# addition arg mapping for compare plot -@functools.wraps(az.plot_compare) -def compareplot(*args, **kwargs): - if "comp_df" in kwargs: - comp_df = kwargs["comp_df"].copy() - else: - args = list(args) - comp_df = args[0].copy() - if "WAIC" in comp_df.columns: - comp_df = comp_df.rename( - index=str, - columns={ - "WAIC": "waic", - "pWAIC": "p_waic", - "dWAIC": "d_waic", - "SE": "se", - "dSE": "dse", - "var_warn": "warning", - }, - ) - elif "LOO" in comp_df.columns: - comp_df = comp_df.rename( - index=str, - columns={ - "LOO": "loo", - "pLOO": "p_loo", - "dLOO": "d_loo", - "SE": "se", - "dSE": "dse", - "shape_warn": "warning", - }, - ) - if "comp_df" in kwargs: - kwargs["comp_df"] = comp_df - else: - args[0] = comp_df - return az.plot_compare(*args, **kwargs) - - from pymc3.plots.posteriorplot import plot_posterior_predictive_glm -# Access to arviz plots: base plots provided by arviz -for plot in az.plots.__all__: - setattr(sys.modules[__name__], plot, map_args(getattr(az.plots, plot))) - -__all__ = tuple(az.plots.__all__) + ( - "autocorrplot", - "compareplot", - "forestplot", - "kdeplot", - "plot_posterior", - "traceplot", - "energyplot", - "densityplot", - "pairplot", - "plot_posterior_predictive_glm", -) +__all__ = ["plot_posterior_predictive_glm"] diff --git a/pymc3/plots/posteriorplot.py b/pymc3/plots/posteriorplot.py index 08ba7f04878..92b341d9cc9 100644 --- a/pymc3/plots/posteriorplot.py +++ b/pymc3/plots/posteriorplot.py @@ -14,6 +14,8 @@ from __future__ import annotations +import warnings + from typing import TYPE_CHECKING, Any, Callable, Optional, Union import matplotlib.pyplot as plt @@ -33,20 +35,33 @@ def plot_posterior_predictive_glm( **kwargs: Any ) -> None: """Plot posterior predictive of a linear model. - :Arguments: - trace: InferenceData or MultiTrace - Output of pm.sample() - eval: - Array over which to evaluate lm - lm: function - Function mapping parameters at different points - to their respective outputs. - input: point, sample - output: estimated value - samples: int - How many posterior samples to draw. - Additional keyword arguments are passed to pylab.plot(). + + Parameters + ---------- + trace: InferenceData or MultiTrace + Output of pm.sample() + eval: + Array over which to evaluate lm + lm: function + Function mapping parameters at different points + to their respective outputs. + input: point, sample + output: estimated value + samples: int + How many posterior samples to draw. + kwargs : mapping, optional + Additional keyword arguments are passed to ``matplotlib.pyplot.plot()``. + + Warnings + -------- + The `plot_posterior_predictive_glm` function will be removed in a future PyMC3 release. """ + warnings.warn( + "The `plot_posterior_predictive_glm` function will migrate to Arviz in a future release. " + "\nKeep up to date with `ArviZ `_ for future updates.", + DeprecationWarning, + ) + if lm is None: lm = lambda x, sample: sample["Intercept"] + sample["x"] * x diff --git a/pymc3/sampling.py b/pymc3/sampling.py index 0dedb877237..2699d7c6d22 100644 --- a/pymc3/sampling.py +++ b/pymc3/sampling.py @@ -416,7 +416,7 @@ def sample( ...: y = pm.Binomial("y", n=n, p=p, observed=h) ...: trace = pm.sample() - In [3]: pm.summary(trace, kind="stats") + In [3]: az.summary(trace, kind="stats") Out[3]: mean sd hdi_3% hdi_97% diff --git a/pymc3/stats/__init__.py b/pymc3/stats/__init__.py deleted file mode 100644 index d4670d67ce9..00000000000 --- a/pymc3/stats/__init__.py +++ /dev/null @@ -1,69 +0,0 @@ -# Copyright 2020 The PyMC Developers -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Statistical utility functions for PyMC3 - -Diagnostics and auxiliary statistical functions are delegated to the ArviZ library, a general -purpose library for "exploratory analysis of Bayesian models." See -https://arviz-devs.github.io/arviz/ for details. -""" -import functools -import warnings - -import arviz as az - - -def map_args(func): - swaps = [("varnames", "var_names")] - - @functools.wraps(func) - def wrapped(*args, **kwargs): - for (old, new) in swaps: - if old in kwargs and new not in kwargs: - warnings.warn( - "Keyword argument `{old}` renamed to `{new}`, and will be removed in " - "pymc3 3.9".format(old=old, new=new) - ) - kwargs[new] = kwargs.pop(old) - return func(*args, **kwargs) - - return wrapped - - -bfmi = map_args(az.bfmi) -compare = map_args(az.compare) -ess = map_args(az.ess) -geweke = map_args(az.geweke) -hpd = map_args(az.hpd) -loo = map_args(az.loo) -mcse = map_args(az.mcse) -r2_score = map_args(az.r2_score) -rhat = map_args(az.rhat) -summary = map_args(az.summary) -waic = map_args(az.waic) - - -__all__ = [ - "bfmi", - "compare", - "ess", - "geweke", - "hpd", - "loo", - "mcse", - "r2_score", - "rhat", - "summary", - "waic", -] diff --git a/pymc3/step_methods/mlda.py b/pymc3/step_methods/mlda.py index f99af282524..559f894f300 100644 --- a/pymc3/step_methods/mlda.py +++ b/pymc3/step_methods/mlda.py @@ -333,7 +333,7 @@ class MLDA(ArrayStepShared): ... tune=100, step=step_method, ... random_seed=123) ... - ... pm.summary(trace, kind="stats") + ... az.summary(trace, kind="stats") mean sd hdi_3% hdi_97% x 0.99 0.987 -0.734 2.992 diff --git a/pymc3/tests/sampler_fixtures.py b/pymc3/tests/sampler_fixtures.py index 318165c6972..fcf66f15569 100644 --- a/pymc3/tests/sampler_fixtures.py +++ b/pymc3/tests/sampler_fixtures.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import arviz as az import numpy as np import numpy.testing as npt import theano.tensor as tt @@ -146,12 +147,12 @@ def setup_class(cls): def test_neff(self): if hasattr(self, "min_n_eff"): - n_eff = pm.ess(self.trace[self.burn :]) + n_eff = az.ess(self.trace[self.burn :]) for var in n_eff: npt.assert_array_less(self.min_n_eff, n_eff[var]) def test_Rhat(self): - rhat = pm.rhat(self.trace[self.burn :]) + rhat = az.rhat(self.trace[self.burn :]) for var in rhat: npt.assert_allclose(rhat[var], 1, rtol=0.01) diff --git a/pymc3/tests/test_examples.py b/pymc3/tests/test_examples.py index 9b741a9674a..d79093b3927 100644 --- a/pymc3/tests/test_examples.py +++ b/pymc3/tests/test_examples.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import arviz as az import matplotlib import numpy as np import pandas as pd @@ -202,7 +203,7 @@ def test_disaster_model(self): # Use slice sampler for means (other variables auto-selected) step = pm.Slice([model.early_mean_log__, model.late_mean_log__]) tr = pm.sample(500, tune=50, start=start, step=step, chains=2) - pm.summary(tr) + az.summary(tr) def test_disaster_model_missing(self): model = build_disaster_model(masked=True) @@ -212,7 +213,7 @@ def test_disaster_model_missing(self): # Use slice sampler for means (other variables auto-selected) step = pm.Slice([model.early_mean_log__, model.late_mean_log__]) tr = pm.sample(500, tune=50, start=start, step=step, chains=2) - pm.summary(tr) + az.summary(tr) class TestGLMLinear(SeededTest):