From 6a586a7487260b8f1074d985ef80073f1f6dc99b Mon Sep 17 00:00:00 2001 From: Du Phan Date: Wed, 14 Feb 2024 22:25:45 -0500 Subject: [PATCH 01/17] Use networkx instead of causalgraphicalmodels --- README.md | 4 +- notebooks/00_preface.ipynb | 8 +- notebooks/01_the_golem_of_prague.ipynb | 4 +- .../02_small_worlds_and_large_worlds.ipynb | 8 +- notebooks/03_sampling_the_imaginary.ipynb | 4 +- notebooks/04_geocentric_models.ipynb | 32 +-- ...y_variables_and_the_spurious_waffles.ipynb | 152 +++++-------- ...he_haunted_dag_and_the_causal_terror.ipynb | 204 ++++++++++-------- notebooks/07_ulysses_compass.ipynb | 42 ++-- notebooks/08_conditional_manatees.ipynb | 28 +-- notebooks/09_markov_chain_monte_carlo.ipynb | 6 +- ...opy_and_the_generalized_linear_model.ipynb | 6 +- notebooks/11_god_spiked_the_integers.ipynb | 4 +- notebooks/12_monsters_and_mixtures.ipynb | 11 +- notebooks/13_models_with_memory.ipynb | 4 +- notebooks/14_adventures_in_covariance.ipynb | 33 ++- ...missing_data_and_other_opportunities.ipynb | 4 +- notebooks/16_generalized_linear_madness.ipynb | 6 +- notebooks/17_horoscopes.ipynb | 4 +- requirements.txt | 2 +- 20 files changed, 290 insertions(+), 276 deletions(-) diff --git a/README.md b/README.md index 4a3162b..caa95ec 100644 --- a/README.md +++ b/README.md @@ -13,10 +13,10 @@ I am a fan of the book [*Statistical Rethinking*](https://xcelab.net/rm/statisti ## Installation -The following tools are used for some analysis and visualizations: [arviz](https://arviz-devs.github.io/arviz/) for [posteriors](https://en.wikipedia.org/wiki/Posterior_probability), [causalgraphicalmodels](https://github.com/ijmbarr/causalgraphicalmodels) and [daft](https://docs.daft-pgm.org/en/latest/) for [causal graphs](https://en.wikipedia.org/wiki/Causal_graph), and (optional) [ete3](http://etetoolkit.org/) for [phylogenetic trees](https://en.wikipedia.org/wiki/Phylogenetic_tree). +The following tools are used for some analysis and visualizations: [arviz](https://arviz-devs.github.io/arviz/) for [posteriors](https://en.wikipedia.org/wiki/Posterior_probability), [networkx](https://networkx.org/) and [daft](https://docs.daft-pgm.org/en/latest/) for [causal graphs](https://en.wikipedia.org/wiki/Causal_graph), and (optional) [ete3](http://etetoolkit.org/) for [phylogenetic trees](https://en.wikipedia.org/wiki/Phylogenetic_tree). ```sh -pip install numpyro arviz causalgraphicalmodels daft +pip install numpyro arviz daft networkx ``` ## Excercises diff --git a/notebooks/00_preface.ipynb b/notebooks/00_preface.ipynb index d0f0e3c..b53894c 100644 --- a/notebooks/00_preface.ipynb +++ b/notebooks/00_preface.ipynb @@ -13,7 +13,7 @@ "metadata": {}, "outputs": [], "source": [ - "!pip install -q numpyro arviz causalgraphicalmodels daft" + "!pip install -q numpyro arviz" ] }, { @@ -231,14 +231,14 @@ }, "source": [ "```sh\n", - "pip install numpyro arviz causalgraphicalmodels daft\n", + "pip install numpyro arviz daft networkx\n", "```" ] } ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -252,7 +252,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.8" + "version": "3.11.6" }, "varInspector": { "cols": { diff --git a/notebooks/01_the_golem_of_prague.ipynb b/notebooks/01_the_golem_of_prague.ipynb index 79a5973..c9fbfd8 100644 --- a/notebooks/01_the_golem_of_prague.ipynb +++ b/notebooks/01_the_golem_of_prague.ipynb @@ -17,7 +17,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -31,7 +31,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.8" + "version": "3.11.6" }, "varInspector": { "cols": { diff --git a/notebooks/02_small_worlds_and_large_worlds.ipynb b/notebooks/02_small_worlds_and_large_worlds.ipynb index 44d0caa..e41c709 100644 --- a/notebooks/02_small_worlds_and_large_worlds.ipynb +++ b/notebooks/02_small_worlds_and_large_worlds.ipynb @@ -21,7 +21,7 @@ "metadata": {}, "outputs": [], "source": [ - "!pip install -q numpyro arviz causalgraphicalmodels daft" + "!pip install -q numpyro arviz" ] }, { @@ -224,7 +224,7 @@ "params = svi_result.params\n", "\n", "# display summary of quadratic approximation\n", - "samples = guide.sample_posterior(random.PRNGKey(1), params, (1000,))\n", + "samples = guide.sample_posterior(random.PRNGKey(1), params, sample_shape=(1000,))\n", "numpyro.diagnostics.print_summary(samples, prob=0.89, group_by_chain=False)" ] }, @@ -323,7 +323,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -337,7 +337,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.8" + "version": "3.11.6" } }, "nbformat": 4, diff --git a/notebooks/03_sampling_the_imaginary.ipynb b/notebooks/03_sampling_the_imaginary.ipynb index 88a18f8..8d9a75e 100644 --- a/notebooks/03_sampling_the_imaginary.ipynb +++ b/notebooks/03_sampling_the_imaginary.ipynb @@ -21,7 +21,7 @@ "metadata": {}, "outputs": [], "source": [ - "!pip install -q numpyro arviz causalgraphicalmodels daft" + "!pip install -q numpyro arviz" ] }, { @@ -816,7 +816,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.10" + "version": "3.11.6" }, "widgets": { "application/vnd.jupyter.widget-state+json": { diff --git a/notebooks/04_geocentric_models.ipynb b/notebooks/04_geocentric_models.ipynb index d3658e0..21b472e 100644 --- a/notebooks/04_geocentric_models.ipynb +++ b/notebooks/04_geocentric_models.ipynb @@ -13,7 +13,7 @@ "metadata": {}, "outputs": [], "source": [ - "!pip install -q numpyro arviz causalgraphicalmodels daft" + "!pip install -q numpyro arviz" ] }, { @@ -904,7 +904,7 @@ } ], "source": [ - "samples = m4_1.sample_posterior(random.PRNGKey(1), p4_1, (1000,))\n", + "samples = m4_1.sample_posterior(random.PRNGKey(1), p4_1, sample_shape=(1000,))\n", "print_summary(samples, 0.89, False)" ] }, @@ -978,7 +978,7 @@ "svi = SVI(model, m4_2, optim.Adam(1), Trace_ELBO(), height=d2.height.values)\n", "svi_result = svi.run(random.PRNGKey(0), 2000)\n", "p4_2 = svi_result.params\n", - "samples = m4_2.sample_posterior(random.PRNGKey(1), p4_2, (1000,))\n", + "samples = m4_2.sample_posterior(random.PRNGKey(1), p4_2, sample_shape=(1000,))\n", "print_summary(samples, 0.89, False)" ] }, @@ -1007,7 +1007,7 @@ } ], "source": [ - "samples = m4_1.sample_posterior(random.PRNGKey(1), p4_1, (1000,))\n", + "samples = m4_1.sample_posterior(random.PRNGKey(1), p4_1, sample_shape=(1000,))\n", "vcov = jnp.cov(jnp.stack(list(samples.values()), axis=0))\n", "vcov" ] @@ -1064,7 +1064,7 @@ } ], "source": [ - "post = m4_1.sample_posterior(random.PRNGKey(1), p4_1, (int(1e4),))\n", + "post = m4_1.sample_posterior(random.PRNGKey(1), p4_1, sample_shape=(int(1e4),))\n", "{latent: list(post[latent][:6]) for latent in post}" ] }, @@ -1369,7 +1369,7 @@ } ], "source": [ - "samples = m4_3.sample_posterior(random.PRNGKey(1), p4_3, (1000,))\n", + "samples = m4_3.sample_posterior(random.PRNGKey(1), p4_3, sample_shape=(1000,))\n", "samples.pop(\"mu\")\n", "print_summary(samples, 0.89, False)" ] @@ -1429,7 +1429,7 @@ ], "source": [ "az.plot_pair(d2[[\"weight\", \"height\"]].to_dict(orient=\"list\"))\n", - "post = m4_3.sample_posterior(random.PRNGKey(1), p4_3, (1000,))\n", + "post = m4_3.sample_posterior(random.PRNGKey(1), p4_3, sample_shape=(1000,))\n", "a_map = jnp.mean(post[\"a\"])\n", "b_map = jnp.mean(post[\"b\"])\n", "x = jnp.linspace(d2.weight.min(), d2.weight.max(), 101)\n", @@ -1464,7 +1464,7 @@ } ], "source": [ - "post = m4_3.sample_posterior(random.PRNGKey(1), p4_3, (1000,))\n", + "post = m4_3.sample_posterior(random.PRNGKey(1), p4_3, sample_shape=(1000,))\n", "{latent: list(post[latent].reshape(-1)[:5]) for latent in post}" ] }, @@ -1539,7 +1539,7 @@ ], "source": [ "# extract 20 samples from the posterior\n", - "post = mN.sample_posterior(random.PRNGKey(1), pN, (20,))\n", + "post = mN.sample_posterior(random.PRNGKey(1), pN, sample_shape=(20,))\n", "\n", "# display raw data and sample size\n", "ax = az.plot_pair(dN[[\"weight\", \"height\"]].to_dict(orient=\"list\"))\n", @@ -1568,7 +1568,7 @@ "metadata": {}, "outputs": [], "source": [ - "post = m4_3.sample_posterior(random.PRNGKey(1), p4_3, (1000,))\n", + "post = m4_3.sample_posterior(random.PRNGKey(1), p4_3, sample_shape=(1000,))\n", "mu_at_50 = post[\"a\"] + post[\"b\"] * (50 - xbar)" ] }, @@ -1797,7 +1797,7 @@ "metadata": {}, "outputs": [], "source": [ - "post = m4_3.sample_posterior(random.PRNGKey(1), p4_3, (1000,))\n", + "post = m4_3.sample_posterior(random.PRNGKey(1), p4_3, sample_shape=(1000,))\n", "mu_link = lambda weight: post[\"a\"] + post[\"b\"] * (weight - xbar)\n", "weight_seq = jnp.arange(start=25, stop=71, step=1)\n", "mu = vmap(mu_link)(weight_seq).T\n", @@ -1924,7 +1924,7 @@ "metadata": {}, "outputs": [], "source": [ - "post = m4_3.sample_posterior(random.PRNGKey(1), p4_3, (1000,))\n", + "post = m4_3.sample_posterior(random.PRNGKey(1), p4_3, sample_shape=(1000,))\n", "weight_seq = jnp.arange(25, 71)\n", "sim_height = vmap(\n", " lambda i, weight: dist.Normal(\n", @@ -2126,7 +2126,7 @@ } ], "source": [ - "samples = m4_5.sample_posterior(random.PRNGKey(1), p4_5, (1000,))\n", + "samples = m4_5.sample_posterior(random.PRNGKey(1), p4_5, sample_shape=(1000,))\n", "print_summary({k: v for k, v in samples.items() if k != \"mu\"}, 0.89, False)" ] }, @@ -2145,7 +2145,7 @@ "source": [ "weight_seq = jnp.linspace(start=-2.2, stop=2, num=30)\n", "pred_dat = {\"weight_s\": weight_seq, \"weight_s2\": weight_seq**2}\n", - "post = m4_5.sample_posterior(random.PRNGKey(1), p4_5, (1000,))\n", + "post = m4_5.sample_posterior(random.PRNGKey(1), p4_5, sample_shape=(1000,))\n", "predictive = Predictive(m4_5.model, post)\n", "mu = predictive(random.PRNGKey(2), **pred_dat)[\"mu\"]\n", "mu_mean = jnp.mean(mu, 0)\n", @@ -2479,7 +2479,7 @@ } ], "source": [ - "post = m4_7.sample_posterior(random.PRNGKey(1), p4_7, (1000,))\n", + "post = m4_7.sample_posterior(random.PRNGKey(1), p4_7, sample_shape=(1000,))\n", "w = jnp.mean(post[\"w\"], 0)\n", "plt.subplot(\n", " xlim=(d2.year.min(), d2.year.max()),\n", @@ -2578,7 +2578,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.10" + "version": "3.11.6" }, "toc": { "base_numbering": 1, diff --git a/notebooks/05_the_many_variables_and_the_spurious_waffles.ipynb b/notebooks/05_the_many_variables_and_the_spurious_waffles.ipynb index 8ba5096..f1bb825 100644 --- a/notebooks/05_the_many_variables_and_the_spurious_waffles.ipynb +++ b/notebooks/05_the_many_variables_and_the_spurious_waffles.ipynb @@ -13,7 +13,7 @@ "metadata": {}, "outputs": [], "source": [ - "!pip install -q numpyro arviz causalgraphicalmodels daft" + "!pip install -q numpyro arviz daft networkx" ] }, { @@ -22,14 +22,16 @@ "metadata": {}, "outputs": [], "source": [ + "import collections\n", + "import itertools\n", "import math\n", "import os\n", "\n", "import arviz as az\n", "import daft\n", "import matplotlib.pyplot as plt\n", + "import networkx as nx\n", "import pandas as pd\n", - "from causalgraphicalmodels import CausalGraphicalModel\n", "\n", "import jax.numpy as jnp\n", "from jax import random\n", @@ -189,7 +191,7 @@ "source": [ "# compute percentile interval of mean\n", "A_seq = jnp.linspace(start=-3, stop=3.2, num=30)\n", - "post = m5_1.sample_posterior(random.PRNGKey(1), p5_1, (1000,))\n", + "post = m5_1.sample_posterior(random.PRNGKey(1), p5_1, sample_shape=(1000,))\n", "post_pred = Predictive(m5_1.model, post)(random.PRNGKey(2), A=A_seq)\n", "mu = post_pred[\"mu\"]\n", "mu_mean = jnp.mean(mu, 0)\n", @@ -254,7 +256,7 @@ "outputs": [ { "data": { - "image/png": "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\n", + "image/png": "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", "text/plain": [ "
" ] @@ -264,18 +266,18 @@ } ], "source": [ - "dag5_1 = CausalGraphicalModel(\n", - " nodes=[\"A\", \"D\", \"M\"], edges=[(\"A\", \"D\"), (\"A\", \"M\"), (\"M\", \"D\")]\n", - ")\n", + "dag5_1 = nx.DiGraph()\n", + "dag5_1.add_edges_from([(\"A\", \"D\"), (\"A\", \"M\"), (\"M\", \"D\")])\n", "pgm = daft.PGM()\n", "coordinates = {\"A\": (0, 0), \"D\": (1, 1), \"M\": (2, 0)}\n", - "for node in dag5_1.dag.nodes:\n", + "for node in dag5_1.nodes:\n", " pgm.add_node(node, node, *coordinates[node])\n", - "for edge in dag5_1.dag.edges:\n", + "for edge in dag5_1.edges:\n", " pgm.add_edge(*edge)\n", "with plt.rc_context({\"figure.constrained_layout.use\": False}):\n", " pgm.render()\n", - "plt.gca().invert_yaxis()" + "plt.gca().invert_yaxis()\n", + "plt.show()" ] }, { @@ -294,20 +296,23 @@ "name": "stdout", "output_type": "stream", "text": [ - "('M', 'D', {'A'})\n" + "D _||_ M | A\n" ] } ], "source": [ - "DMA_dag2 = CausalGraphicalModel(nodes=[\"A\", \"D\", \"M\"], edges=[(\"A\", \"D\"), (\"A\", \"M\")])\n", - "all_independencies = DMA_dag2.get_all_independence_relationships()\n", - "for s in all_independencies:\n", - " if all(\n", - " t[0] != s[0] or t[1] != s[1] or not t[2].issubset(s[2])\n", - " for t in all_independencies\n", - " if t != s\n", - " ):\n", - " print(s)" + "DMA_dag2 = nx.DiGraph()\n", + "DMA_dag2.add_edges_from([(\"A\", \"D\"), (\"A\", \"M\")])\n", + "conditional_independencies = collections.defaultdict(list)\n", + "for edge in itertools.combinations(sorted(DMA_dag2.nodes), 2):\n", + " remaining = sorted(set(DMA_dag2.nodes) - set(edge))\n", + " for size in range(len(remaining) + 1):\n", + " for subset in itertools.combinations(remaining, size):\n", + " if any(cond.issubset(set(subset)) for cond in conditional_independencies[edge]):\n", + " continue\n", + " if nx.d_separated(DMA_dag2, {edge[0]}, {edge[1]}, set(subset)):\n", + " conditional_independencies[edge].append(set(subset))\n", + " print(f\"{edge[0]} _||_ {edge[1]}\" + (f\" | {' '.join(subset)}\" if subset else \"\"))" ] }, { @@ -323,17 +328,18 @@ "metadata": {}, "outputs": [], "source": [ - "DMA_dag2 = CausalGraphicalModel(\n", - " nodes=[\"A\", \"D\", \"M\"], edges=[(\"A\", \"D\"), (\"A\", \"M\"), (\"M\", \"D\")]\n", - ")\n", - "all_independencies = DMA_dag2.get_all_independence_relationships()\n", - "for s in all_independencies:\n", - " if all(\n", - " t[0] != s[0] or t[1] != s[1] or not t[2].issubset(s[2])\n", - " for t in all_independencies\n", - " if t != s\n", - " ):\n", - " print(s)" + "DMA_dag1 = nx.DiGraph()\n", + "DMA_dag1.add_edges_from([(\"A\", \"D\"), (\"A\", \"M\"), (\"M\", \"D\")])\n", + "conditional_independencies = collections.defaultdict(list)\n", + "for edge in itertools.combinations(sorted(DMA_dag1.nodes), 2):\n", + " remaining = sorted(set(DMA_dag1.nodes) - set(edge))\n", + " for size in range(len(remaining) + 1):\n", + " for subset in itertools.combinations(remaining, size):\n", + " if any(cond.issubset(set(subset)) for cond in conditional_independencies[edge]):\n", + " continue\n", + " if nx.d_separated(DMA_dag1, {edge[0]}, {edge[1]}, set(subset)):\n", + " conditional_independencies[edge].append(set(subset))\n", + " print(f\"{edge[0]} _||_ {edge[1]}\" + (f\" | {' '.join(subset)}\" if subset else \"\"))" ] }, { @@ -435,7 +441,7 @@ ")\n", "svi_result = svi.run(random.PRNGKey(0), 1000)\n", "p5_3 = svi_result.params\n", - "post = m5_3.sample_posterior(random.PRNGKey(1), p5_3, (1000,))\n", + "post = m5_3.sample_posterior(random.PRNGKey(1), p5_3, sample_shape=(1000,))\n", "print_summary(post, 0.89, False)" ] }, @@ -464,30 +470,9 @@ ], "source": [ "coeftab = {\n", - " \"m5.1\": m5_1.sample_posterior(\n", - " random.PRNGKey(1),\n", - " p5_1,\n", - " (\n", - " 1,\n", - " 1000,\n", - " ),\n", - " ),\n", - " \"m5.2\": m5_2.sample_posterior(\n", - " random.PRNGKey(2),\n", - " p5_2,\n", - " (\n", - " 1,\n", - " 1000,\n", - " ),\n", - " ),\n", - " \"m5.3\": m5_3.sample_posterior(\n", - " random.PRNGKey(3),\n", - " p5_3,\n", - " (\n", - " 1,\n", - " 1000,\n", - " ),\n", - " ),\n", + " \"m5.1\": m5_1.sample_posterior(random.PRNGKey(1), p5_1, sample_shape=(1, 1000)),\n", + " \"m5.2\": m5_2.sample_posterior(random.PRNGKey(2), p5_2, sample_shape=(1, 1000)),\n", + " \"m5.3\": m5_3.sample_posterior(random.PRNGKey(3), p5_3, sample_shape=(1, 1000)),\n", "}\n", "az.plot_forest(\n", " list(coeftab.values()),\n", @@ -565,7 +550,7 @@ "metadata": {}, "outputs": [], "source": [ - "post = m5_4.sample_posterior(random.PRNGKey(1), p5_4, (1000,))\n", + "post = m5_4.sample_posterior(random.PRNGKey(1), p5_4, sample_shape=(1000,))\n", "post_pred = Predictive(m5_4.model, post)(random.PRNGKey(2), A=d.A.values)\n", "mu = post_pred[\"mu\"]\n", "mu_mean = jnp.mean(mu, 0)\n", @@ -786,7 +771,7 @@ "sim_dat = dict(A=A_seq)\n", "\n", "# simulate M and then D, using A_seq\n", - "post = m5_3_A.sample_posterior(random.PRNGKey(1), p5_3_A, (1000,))\n", + "post = m5_3_A.sample_posterior(random.PRNGKey(1), p5_3_A, sample_shape=(1000,))\n", "s = Predictive(m5_3_A.model, post)(random.PRNGKey(2), **sim_dat)" ] }, @@ -926,7 +911,7 @@ "metadata": {}, "outputs": [], "source": [ - "post = m5_3_A.sample_posterior(random.PRNGKey(1), p5_3_A, (1000,))\n", + "post = m5_3_A.sample_posterior(random.PRNGKey(1), p5_3_A, sample_shape=(1000,))\n", "post = {k: v[..., None] for k, v in post.items()}\n", "M_sim = dist.Normal(post[\"aM\"] + post[\"bAM\"] * A_seq).sample(random.PRNGKey(1))" ] @@ -1379,7 +1364,7 @@ } ], "source": [ - "post = m5_5.sample_posterior(random.PRNGKey(1), p5_5, (1000,))\n", + "post = m5_5.sample_posterior(random.PRNGKey(1), p5_5, sample_shape=(1000,))\n", "print_summary(post, 0.89, False)" ] }, @@ -1408,7 +1393,7 @@ ], "source": [ "xseq = jnp.linspace(start=dcc.N.min() - 0.15, stop=dcc.N.max() + 0.15, num=30)\n", - "post = m5_5.sample_posterior(random.PRNGKey(1), p5_5, (1000,))\n", + "post = m5_5.sample_posterior(random.PRNGKey(1), p5_5, sample_shape=(1000,))\n", "post_pred = Predictive(m5_5.model, post)(random.PRNGKey(2), N=xseq)\n", "mu = post_pred[\"mu\"]\n", "mu_mean = jnp.mean(mu, 0)\n", @@ -1481,7 +1466,7 @@ "svi = SVI(model, m5_6, optim.Adam(1), Trace_ELBO(), M=dcc.M.values, K=dcc.K.values)\n", "svi_result = svi.run(random.PRNGKey(0), 1000)\n", "p5_6 = svi_result.params\n", - "post = m5_6.sample_posterior(random.PRNGKey(1), p5_6, (1000,))\n", + "post = m5_6.sample_posterior(random.PRNGKey(1), p5_6, sample_shape=(1000,))\n", "print_summary(post, 0.89, False)" ] }, @@ -1557,7 +1542,7 @@ ")\n", "svi_result = svi.run(random.PRNGKey(0), 1000)\n", "p5_7 = svi_result.params\n", - "post = m5_7.sample_posterior(random.PRNGKey(1), p5_7, (1000,))\n", + "post = m5_7.sample_posterior(random.PRNGKey(1), p5_7, sample_shape=(1000,))\n", "print_summary(post, 0.89, False)" ] }, @@ -1586,30 +1571,9 @@ ], "source": [ "coeftab = {\n", - " \"m5.5\": m5_5.sample_posterior(\n", - " random.PRNGKey(1),\n", - " p5_5,\n", - " (\n", - " 1,\n", - " 1000,\n", - " ),\n", - " ),\n", - " \"m5.6\": m5_6.sample_posterior(\n", - " random.PRNGKey(2),\n", - " p5_6,\n", - " (\n", - " 1,\n", - " 1000,\n", - " ),\n", - " ),\n", - " \"m5.7\": m5_7.sample_posterior(\n", - " random.PRNGKey(3),\n", - " p5_7,\n", - " (\n", - " 1,\n", - " 1000,\n", - " ),\n", - " ),\n", + " \"m5.5\": m5_5.sample_posterior(random.PRNGKey(1), p5_5, sample_shape=(1, 1000)),\n", + " \"m5.6\": m5_6.sample_posterior(random.PRNGKey(2), p5_6, sample_shape=(1, 1000)),\n", + " \"m5.7\": m5_7.sample_posterior(random.PRNGKey(3), p5_7, sample_shape=(1, 1000)),\n", "}\n", "az.plot_forest(\n", " list(coeftab.values()),\n", @@ -1645,7 +1609,7 @@ ], "source": [ "xseq = jnp.linspace(start=dcc.N.min() - 0.15, stop=dcc.N.max() + 0.15, num=30)\n", - "post = m5_7.sample_posterior(random.PRNGKey(1), p5_7, (1000,))\n", + "post = m5_7.sample_posterior(random.PRNGKey(1), p5_7, sample_shape=(1000,))\n", "post_pred = Predictive(m5_7.model, post)(random.PRNGKey(2), M=0, N=xseq)\n", "mu = post_pred[\"mu\"]\n", "mu_mean = jnp.mean(mu, 0)\n", @@ -1978,7 +1942,7 @@ ")\n", "svi_result = svi.run(random.PRNGKey(0), 2000)\n", "p5_8 = svi_result.params\n", - "post = m5_8.sample_posterior(random.PRNGKey(1), p5_8, (1000,))\n", + "post = m5_8.sample_posterior(random.PRNGKey(1), p5_8, sample_shape=(1000,))\n", "print_summary(post, 0.89, False)" ] }, @@ -2009,7 +1973,7 @@ } ], "source": [ - "post = m5_8.sample_posterior(random.PRNGKey(1), p5_8, (1000,))\n", + "post = m5_8.sample_posterior(random.PRNGKey(1), p5_8, sample_shape=(1000,))\n", "post[\"diff_fm\"] = post[\"a\"][:, 0] - post[\"a\"][:, 1]\n", "print_summary(post, 0.89, False)" ] @@ -2107,7 +2071,7 @@ ")\n", "svi_result = svi.run(random.PRNGKey(0), 1000)\n", "p5_9 = svi_result.params\n", - "post = m5_9.sample_posterior(random.PRNGKey(1), p5_9, (1000,))\n", + "post = m5_9.sample_posterior(random.PRNGKey(1), p5_9, sample_shape=(1000,))\n", "labels = [\"a[\" + str(i) + \"]:\" + s for i, s in enumerate(sorted(d.clade.unique()))]\n", "az.plot_forest({\"a\": post[\"a\"][None, ...]}, hdi_prob=0.89)\n", "plt.gca().set(yticklabels=labels[::-1], xlabel=\"expected kcal (std)\")\n", @@ -2177,9 +2141,9 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python (pydata)", "language": "python", - "name": "python3" + "name": "pydata" }, "language_info": { "codemirror_mode": { @@ -2191,7 +2155,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.8" + "version": "3.10.13" } }, "nbformat": 4, diff --git a/notebooks/06_the_haunted_dag_and_the_causal_terror.ipynb b/notebooks/06_the_haunted_dag_and_the_causal_terror.ipynb index 055ef70..934b8b1 100644 --- a/notebooks/06_the_haunted_dag_and_the_causal_terror.ipynb +++ b/notebooks/06_the_haunted_dag_and_the_causal_terror.ipynb @@ -13,7 +13,7 @@ "metadata": {}, "outputs": [], "source": [ - "!pip install -q numpyro arviz causalgraphicalmodels daft" + "!pip install -q numpyro arviz daft networkx" ] }, { @@ -22,14 +22,16 @@ "metadata": {}, "outputs": [], "source": [ + "import collections\n", + "import itertools\n", "import os\n", "import warnings\n", "\n", "import arviz as az\n", "import daft\n", "import matplotlib.pyplot as plt\n", + "import networkx as nx\n", "import pandas as pd\n", - "from causalgraphicalmodels import CausalGraphicalModel\n", "\n", "import jax.numpy as jnp\n", "from jax import lax, random\n", @@ -173,7 +175,7 @@ ")\n", "svi_result = svi.run(random.PRNGKey(0), 2000)\n", "p6_1 = svi_result.params\n", - "post = m6_1.sample_posterior(random.PRNGKey(1), p6_1, (1000,))\n", + "post = m6_1.sample_posterior(random.PRNGKey(1), p6_1, sample_shape=(1000,))\n", "print_summary(post, 0.89, False)" ] }, @@ -229,7 +231,7 @@ } ], "source": [ - "post = m6_1.sample_posterior(random.PRNGKey(1), p6_1, (1000,))\n", + "post = m6_1.sample_posterior(random.PRNGKey(1), p6_1, sample_shape=(1000,))\n", "az.plot_pair(post, var_names=[\"br\", \"bl\"], scatter_kwargs={\"alpha\": 0.1})\n", "plt.show()" ] @@ -315,7 +317,7 @@ ")\n", "svi_result = svi.run(random.PRNGKey(0), 1000)\n", "p6_2 = svi_result.params\n", - "post = m6_2.sample_posterior(random.PRNGKey(1), p6_2, (1000,))\n", + "post = m6_2.sample_posterior(random.PRNGKey(1), p6_2, sample_shape=(1000,))\n", "print_summary(post, 0.89, False)" ] }, @@ -408,9 +410,9 @@ "svi_result = svi.run(random.PRNGKey(0), 1000)\n", "p6_4 = svi_result.params\n", "\n", - "post = m6_3.sample_posterior(random.PRNGKey(1), p6_3, (1000,))\n", + "post = m6_3.sample_posterior(random.PRNGKey(1), p6_3, sample_shape=(1000,))\n", "print_summary(post, 0.89, False)\n", - "post = m6_4.sample_posterior(random.PRNGKey(1), p6_4, (1000,))\n", + "post = m6_4.sample_posterior(random.PRNGKey(1), p6_4, sample_shape=(1000,))\n", "print_summary(post, 0.89, False)" ] }, @@ -463,7 +465,7 @@ ")\n", "svi_result = svi.run(random.PRNGKey(0), 1000)\n", "p6_5 = svi_result.params\n", - "post = m6_5.sample_posterior(random.PRNGKey(1), p6_5, (1000,))\n", + "post = m6_5.sample_posterior(random.PRNGKey(1), p6_5, sample_shape=(1000,))\n", "print_summary(post, 0.89, False)" ] }, @@ -546,7 +548,7 @@ " )\n", " svi_result = svi.run(random.PRNGKey(3 * i + 1), 20000, progress_bar=False)\n", " params = svi_result.params\n", - " samples = m.sample_posterior(random.PRNGKey(3 * i + 2), params, (1000,))\n", + " samples = m.sample_posterior(random.PRNGKey(3 * i + 2), params, sample_shape=(1000,))\n", " vcov = jnp.cov(jnp.stack(list(samples.values()), axis=0))\n", " stddev = jnp.sqrt(jnp.diag(vcov)) # stddev of parameter\n", " return dict(zip(samples.keys(), stddev))[\"b_perc.fat\"]\n", @@ -681,7 +683,7 @@ "svi = SVI(model, m6_6, optim.Adam(1), Trace_ELBO(), h0=d.h0.values, h1=d.h1.values)\n", "svi_result = svi.run(random.PRNGKey(0), 1000)\n", "p6_6 = svi_result.params\n", - "post = m6_6.sample_posterior(random.PRNGKey(1), p6_6, (1000,))\n", + "post = m6_6.sample_posterior(random.PRNGKey(1), p6_6, sample_shape=(1000,))\n", "print_summary(post, 0.89, False)" ] }, @@ -742,7 +744,7 @@ ")\n", "svi_result = svi.run(random.PRNGKey(0), 1000)\n", "p6_7 = svi_result.params\n", - "post = m6_7.sample_posterior(random.PRNGKey(1), p6_7, (1000,))\n", + "post = m6_7.sample_posterior(random.PRNGKey(1), p6_7, sample_shape=(1000,))\n", "print_summary(post, 0.89, False)" ] }, @@ -800,7 +802,7 @@ ")\n", "svi_result = svi.run(random.PRNGKey(0), 1000)\n", "p6_8 = svi_result.params\n", - "post = m6_8.sample_posterior(random.PRNGKey(1), p6_8, (1000,))\n", + "post = m6_8.sample_posterior(random.PRNGKey(1), p6_8, sample_shape=(1000,))\n", "print_summary(post, 0.89, False)" ] }, @@ -813,12 +815,12 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 4, "metadata": {}, "outputs": [ { "data": { - "image/png": "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\n", + "image/png": "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", "text/plain": [ "
" ] @@ -828,14 +830,13 @@ } ], "source": [ - "plant_dag = CausalGraphicalModel(\n", - " nodes=[\"H0\", \"H1\", \"F\", \"T\"], edges=[(\"H0\", \"H1\"), (\"F\", \"H1\"), (\"T\", \"F\")]\n", - ")\n", + "plant_dag = nx.DiGraph()\n", + "plant_dag.add_edges_from([(\"H0\", \"H1\"), (\"F\", \"H1\"), (\"T\", \"F\")])\n", "pgm = daft.PGM()\n", "coordinates = {\"H0\": (0, 0), \"T\": (4, 0), \"F\": (3, 0), \"H1\": (2, 0)}\n", - "for node in plant_dag.dag.nodes:\n", + "for node in plant_dag.nodes:\n", " pgm.add_node(node, node, *coordinates[node])\n", - "for edge in plant_dag.dag.edges:\n", + "for edge in plant_dag.edges:\n", " pgm.add_edge(*edge)\n", "with plt.rc_context({\"figure.constrained_layout.use\": False}):\n", " pgm.render()" @@ -850,28 +851,30 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 37, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "('H0', 'T', set())\n", - "('H0', 'F', set())\n", - "('H1', 'T', {'F'})\n" + "F _||_ H0\n", + "H0 _||_ T\n", + "H1 _||_ T | F\n" ] } ], "source": [ - "all_independencies = plant_dag.get_all_independence_relationships()\n", - "for s in all_independencies:\n", - " if all(\n", - " t[0] != s[0] or t[1] != s[1] or not t[2].issubset(s[2])\n", - " for t in all_independencies\n", - " if t != s\n", - " ):\n", - " print(s)" + "conditional_independencies = collections.defaultdict(list)\n", + "for edge in itertools.combinations(sorted(plant_dag.nodes), 2):\n", + " remaining = sorted(set(plant_dag.nodes) - set(edge))\n", + " for size in range(len(remaining) + 1):\n", + " for subset in itertools.combinations(remaining, size):\n", + " if any(cond.issubset(set(subset)) for cond in conditional_independencies[edge]):\n", + " continue\n", + " if nx.d_separated(plant_dag, {edge[0]}, {edge[1]}, set(subset)):\n", + " conditional_independencies[edge].append(set(subset))\n", + " print(f\"{edge[0]} _||_ {edge[1]}\" + (f\" | {' '.join(subset)}\" if subset else \"\"))" ] }, { @@ -1027,7 +1030,7 @@ ")\n", "svi_result = svi.run(random.PRNGKey(0), 1000)\n", "p6_9 = svi_result.params\n", - "post = m6_9.sample_posterior(random.PRNGKey(1), p6_9, (1000,))\n", + "post = m6_9.sample_posterior(random.PRNGKey(1), p6_9, sample_shape=(1000,))\n", "print_summary(post, 0.89, False)" ] }, @@ -1083,7 +1086,7 @@ ")\n", "svi_result = svi.run(random.PRNGKey(0), 1000)\n", "p6_10 = svi_result.params\n", - "post = m6_10.sample_posterior(random.PRNGKey(1), p6_10, (1000,))\n", + "post = m6_10.sample_posterior(random.PRNGKey(1), p6_10, sample_shape=(1000,))\n", "print_summary(post, 0.89, False)" ] }, @@ -1183,7 +1186,7 @@ ")\n", "svi_result = svi.run(random.PRNGKey(0), 1000)\n", "p6_11 = svi_result.params\n", - "post = m6_11.sample_posterior(random.PRNGKey(1), p6_11, (1000,))\n", + "post = m6_11.sample_posterior(random.PRNGKey(1), p6_11, sample_shape=(1000,))\n", "print_summary(post, 0.89, False)" ] }, @@ -1245,7 +1248,7 @@ ")\n", "svi_result = svi.run(random.PRNGKey(0), 1000)\n", "p6_12 = svi_result.params\n", - "post = m6_12.sample_posterior(random.PRNGKey(1), p6_12, (1000,))\n", + "post = m6_12.sample_posterior(random.PRNGKey(1), p6_12, sample_shape=(1000,))\n", "print_summary(post, 0.89, False)" ] }, @@ -1265,29 +1268,42 @@ "name": "stdout", "output_type": "stream", "text": [ - "frozenset({'C'})\n", - "frozenset({'A'})\n" + "{'A'}\n", + "{'C'}\n" ] } ], "source": [ - "dag_6_1 = CausalGraphicalModel(\n", - " nodes=[\"X\", \"Y\", \"C\", \"U\", \"B\", \"A\"],\n", - " edges=[\n", - " (\"X\", \"Y\"),\n", - " (\"U\", \"X\"),\n", - " (\"A\", \"U\"),\n", - " (\"A\", \"C\"),\n", - " (\"C\", \"Y\"),\n", - " (\"U\", \"B\"),\n", - " (\"C\", \"B\"),\n", - " ],\n", - ")\n", - "all_adjustment_sets = dag_6_1.get_all_backdoor_adjustment_sets(\"X\", \"Y\")\n", - "for s in all_adjustment_sets:\n", - " if all(not t.issubset(s) for t in all_adjustment_sets if t != s):\n", - " if s != {\"U\"}:\n", - " print(s)" + "dag_6_1 = nx.DiGraph()\n", + "dag_6_1.add_edges_from(\n", + " [(\"X\", \"Y\"), (\"U\", \"X\"), (\"A\", \"U\"), (\"A\", \"C\"), (\"C\", \"Y\"), (\"U\", \"B\"), (\"C\", \"B\")])\n", + "backdoor_paths = [path for path in nx.all_simple_paths(dag_6_1.to_undirected(), \"X\", \"Y\")\n", + " if dag_6_1.has_edge(path[1], \"X\")]\n", + "remaining = sorted(set(dag_6_1.nodes) - {\"X\", \"Y\", \"U\"} - set(nx.descendants(dag_6_1, \"X\")))\n", + "adjustment_sets = []\n", + "for size in range(len(remaining) + 1):\n", + " for subset in itertools.combinations(remaining, size):\n", + " subset = set(subset)\n", + " if any(s.issubset(subset) for s in adjustment_sets):\n", + " continue\n", + " need_adjust = True\n", + " for path in backdoor_paths:\n", + " d_separated = False\n", + " for x, z, y in zip(path[:-2], path[1:-1], path[2:]):\n", + " if dag_6_1.has_edge(x, z) and dag_6_1.has_edge(y, z):\n", + " if set(nx.descendants(dag_6_1, z)) & subset:\n", + " continue\n", + " d_separated = z not in subset\n", + " else:\n", + " d_separated = z in subset\n", + " if d_separated:\n", + " break\n", + " if not d_separated:\n", + " need_adjust = False\n", + " break\n", + " if need_adjust:\n", + " adjustment_sets.append(subset)\n", + " print(subset)" ] }, { @@ -1306,28 +1322,42 @@ "name": "stdout", "output_type": "stream", "text": [ - "frozenset({'A', 'M'})\n", - "frozenset({'S'})\n" + "{'S'}\n", + "{'A', 'M'}\n" ] } ], "source": [ - "dag_6_2 = CausalGraphicalModel(\n", - " nodes=[\"S\", \"A\", \"D\", \"M\", \"W\"],\n", - " edges=[\n", - " (\"S\", \"A\"),\n", - " (\"A\", \"D\"),\n", - " (\"S\", \"M\"),\n", - " (\"M\", \"D\"),\n", - " (\"S\", \"W\"),\n", - " (\"W\", \"D\"),\n", - " (\"A\", \"M\"),\n", - " ],\n", - ")\n", - "all_adjustment_sets = dag_6_2.get_all_backdoor_adjustment_sets(\"W\", \"D\")\n", - "for s in all_adjustment_sets:\n", - " if all(not t.issubset(s) for t in all_adjustment_sets if t != s):\n", - " print(s)" + "dag_6_2 = nx.DiGraph()\n", + "dag_6_2.add_edges_from(\n", + " [(\"S\", \"A\"), (\"A\", \"D\"), (\"S\", \"M\"), (\"M\", \"D\"), (\"S\", \"W\"), (\"W\", \"D\"), (\"A\", \"M\")])\n", + "backdoor_paths = [path for path in nx.all_simple_paths(dag_6_2.to_undirected(), \"W\", \"D\")\n", + " if dag_6_2.has_edge(path[1], \"W\")]\n", + "remaining = sorted(set(dag_6_2.nodes) - {\"W\", \"D\"} - set(nx.descendants(dag_6_2, \"W\")))\n", + "adjustment_sets = []\n", + "for size in range(len(remaining) + 1):\n", + " for subset in itertools.combinations(remaining, size):\n", + " subset = set(subset)\n", + " if any(s.issubset(subset) for s in adjustment_sets):\n", + " continue\n", + " need_adjust = True\n", + " for path in backdoor_paths:\n", + " d_separated = False\n", + " for x, z, y in zip(path[:-2], path[1:-1], path[2:]):\n", + " if dag_6_2.has_edge(x, z) and dag_6_2.has_edge(y, z):\n", + " if set(nx.descendants(dag_6_2, z)) & subset:\n", + " continue\n", + " d_separated = z not in subset\n", + " else:\n", + " d_separated = z in subset\n", + " if d_separated:\n", + " break\n", + " if not d_separated:\n", + " need_adjust = False\n", + " break\n", + " if need_adjust:\n", + " adjustment_sets.append(subset)\n", + " print(subset)" ] }, { @@ -1346,29 +1376,31 @@ "name": "stdout", "output_type": "stream", "text": [ - "('S', 'D', {'A', 'W', 'M'})\n", - "('M', 'W', {'S'})\n", - "('A', 'W', {'S'})\n" + "A _||_ W | S\n", + "D _||_ S | A M W\n", + "M _||_ W | S\n" ] } ], "source": [ - "all_independencies = dag_6_2.get_all_independence_relationships()\n", - "for s in all_independencies:\n", - " if all(\n", - " t[0] != s[0] or t[1] != s[1] or not t[2].issubset(s[2])\n", - " for t in all_independencies\n", - " if t != s\n", - " ):\n", - " print(s)" + "conditional_independencies = collections.defaultdict(list)\n", + "for edge in itertools.combinations(sorted(dag_6_2.nodes), 2):\n", + " remaining = sorted(set(dag_6_2.nodes) - set(edge))\n", + " for size in range(len(remaining) + 1):\n", + " for subset in itertools.combinations(remaining, size):\n", + " if any(cond.issubset(set(subset)) for cond in conditional_independencies[edge]):\n", + " continue\n", + " if nx.d_separated(dag_6_2, {edge[0]}, {edge[1]}, set(subset)):\n", + " conditional_independencies[edge].append(set(subset))\n", + " print(f\"{edge[0]} _||_ {edge[1]}\" + (f\" | {' '.join(subset)}\" if subset else \"\"))" ] } ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python (pydata)", "language": "python", - "name": "python3" + "name": "pydata" }, "language_info": { "codemirror_mode": { @@ -1380,7 +1412,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.8" + "version": "3.10.13" } }, "nbformat": 4, diff --git a/notebooks/07_ulysses_compass.ipynb b/notebooks/07_ulysses_compass.ipynb index 8c9b7eb..285fae2 100644 --- a/notebooks/07_ulysses_compass.ipynb +++ b/notebooks/07_ulysses_compass.ipynb @@ -13,7 +13,7 @@ "metadata": {}, "outputs": [], "source": [ - "!pip install -q numpyro arviz causalgraphicalmodels daft" + "!pip install -q numpyro arviz" ] }, { @@ -175,7 +175,7 @@ ")\n", "svi_result = svi.run(random.PRNGKey(0), 1000)\n", "p7_1_OLS = svi_result.params\n", - "post = m7_1_OLS.sample_posterior(random.PRNGKey(1), p7_1_OLS, (1000,))" + "post = m7_1_OLS.sample_posterior(random.PRNGKey(1), p7_1_OLS, sample_shape=(1000,))" ] }, { @@ -202,7 +202,7 @@ } ], "source": [ - "post = m7_1.sample_posterior(random.PRNGKey(12), p7_1, (1000,))\n", + "post = m7_1.sample_posterior(random.PRNGKey(12), p7_1, sample_shape=(1000,))\n", "s = Predictive(m7_1.model, post)(random.PRNGKey(2), d.mass_std.values)\n", "r = jnp.mean(s[\"brain_std\"], 0) - d.brain_std.values\n", "resid_var = jnp.var(r, ddof=1)\n", @@ -225,7 +225,7 @@ "source": [ "def R2_is_bad(quap_fit):\n", " quap, params = quap_fit\n", - " post = quap.sample_posterior(random.PRNGKey(1), params, (1000,))\n", + " post = quap.sample_posterior(random.PRNGKey(1), params, sample_shape=(1000,))\n", " s = Predictive(quap.model, post)(random.PRNGKey(2), d.mass_std.values)\n", " r = jnp.mean(s[\"brain_std\"], 0) - d.brain_std.values\n", " return 1 - jnp.var(r, ddof=1) / jnp.var(d.brain_std.values, ddof=1)" @@ -443,7 +443,7 @@ } ], "source": [ - "post = m7_1.sample_posterior(random.PRNGKey(1), p7_1, (1000,))\n", + "post = m7_1.sample_posterior(random.PRNGKey(1), p7_1, sample_shape=(1000,))\n", "mass_seq = jnp.linspace(d.mass_std.min(), d.mass_std.max(), num=100)\n", "l = Predictive(m7_1.model, post, return_sites=[\"mu\"])(\n", " random.PRNGKey(2), mass_std=mass_seq\n", @@ -528,7 +528,7 @@ ], "source": [ "def lppd_fn(seed, quad, params, num_samples=1000):\n", - " post = quad.sample_posterior(random.PRNGKey(1), params, (num_samples,))\n", + " post = quad.sample_posterior(random.PRNGKey(1), params, sample_shape=(num_samples,))\n", " logprob = log_likelihood(quad.model, post, d.mass_std.values, d.brain_std.values)\n", " logprob = logprob[\"brain_std\"]\n", " return logsumexp(logprob, 0) - jnp.log(logprob.shape[0])\n", @@ -836,7 +836,7 @@ ")\n", "svi_result = svi.run(random.PRNGKey(0), 5000)\n", "params = svi_result.params\n", - "post = m.sample_posterior(random.PRNGKey(94), params, (1000,))" + "post = m.sample_posterior(random.PRNGKey(94), params, sample_shape=(1000,))" ] }, { @@ -1070,7 +1070,7 @@ "svi_result = svi.run(random.PRNGKey(0), 1000)\n", "p6_8 = svi_result.params\n", "\n", - "post = m6_7.sample_posterior(random.PRNGKey(11), p6_7, (1000,))\n", + "post = m6_7.sample_posterior(random.PRNGKey(11), p6_7, sample_shape=(1000,))\n", "logprob = log_likelihood(\n", " m6_7.model,\n", " post,\n", @@ -1197,10 +1197,10 @@ } ], "source": [ - "post = m6_6.sample_posterior(random.PRNGKey(77), p6_6, (1000,))\n", + "post = m6_6.sample_posterior(random.PRNGKey(77), p6_6, sample_shape=(1000,))\n", "logprob = log_likelihood(m6_6.model, post, h0=d.h0.values, h1=d.h1.values)\n", "az6_6 = az.from_dict({}, log_likelihood={\"h1\": logprob[\"h1\"][None, ...]})\n", - "post = m6_7.sample_posterior(random.PRNGKey(77), p6_7, (1000,))\n", + "post = m6_7.sample_posterior(random.PRNGKey(77), p6_7, sample_shape=(1000,))\n", "logprob = log_likelihood(\n", " m6_7.model,\n", " post,\n", @@ -1210,7 +1210,7 @@ " h1=d.h1.values,\n", ")\n", "az6_7 = az.from_dict({}, log_likelihood={\"h1\": logprob[\"h1\"][None, ...]})\n", - "post = m6_8.sample_posterior(random.PRNGKey(77), p6_8, (1000,))\n", + "post = m6_8.sample_posterior(random.PRNGKey(77), p6_8, sample_shape=(1000,))\n", "logprob = log_likelihood(\n", " m6_8.model, post, treatment=d.treatment.values, h0=d.h0.values, h1=d.h1.values\n", ")\n", @@ -1252,7 +1252,7 @@ } ], "source": [ - "post = m6_7.sample_posterior(random.PRNGKey(91), p6_7, (1000,))\n", + "post = m6_7.sample_posterior(random.PRNGKey(91), p6_7, sample_shape=(1000,))\n", "logprob = log_likelihood(\n", " m6_7.model,\n", " post,\n", @@ -1367,7 +1367,7 @@ } ], "source": [ - "post = m6_6.sample_posterior(random.PRNGKey(92), p6_6, (1000,))\n", + "post = m6_6.sample_posterior(random.PRNGKey(92), p6_6, sample_shape=(1000,))\n", "logprob = log_likelihood(m6_6.model, post, h0=d.h0.values, h1=d.h1.values)\n", "az6_6 = az.from_dict({}, log_likelihood={\"h1\": logprob[\"h1\"][None, ...]})\n", "waic_m6_6 = az.waic(az6_6, pointwise=True, scale=\"deviance\")\n", @@ -1459,11 +1459,11 @@ } ], "source": [ - "post = m6_6.sample_posterior(random.PRNGKey(93), p6_6, (1000,))\n", + "post = m6_6.sample_posterior(random.PRNGKey(93), p6_6, sample_shape=(1000,))\n", "logprob = log_likelihood(m6_6.model, post, h0=d.h0.values, h1=d.h1.values)\n", "az6_6 = az.from_dict({}, log_likelihood={\"h1\": logprob[\"h1\"][None, ...]})\n", "waic_m6_6 = az.waic(az6_6, pointwise=True, scale=\"deviance\")\n", - "post = m6_7.sample_posterior(random.PRNGKey(93), p6_7, (1000,))\n", + "post = m6_7.sample_posterior(random.PRNGKey(93), p6_7, sample_shape=(1000,))\n", "logprob = log_likelihood(\n", " m6_7.model,\n", " post,\n", @@ -1474,7 +1474,7 @@ ")\n", "az6_7 = az.from_dict({}, log_likelihood={\"h1\": logprob[\"h1\"][None, ...]})\n", "waic_m6_7 = az.waic(az6_7, pointwise=True, scale=\"deviance\")\n", - "post = m6_8.sample_posterior(random.PRNGKey(93), p6_8, (1000,))\n", + "post = m6_8.sample_posterior(random.PRNGKey(93), p6_8, sample_shape=(1000,))\n", "logprob = log_likelihood(\n", " m6_8.model, post, treatment=d.treatment.values, h0=d.h0.values, h1=d.h1.values\n", ")\n", @@ -1683,19 +1683,19 @@ } ], "source": [ - "post = m5_1.sample_posterior(random.PRNGKey(24071847), p5_1, (1000,))\n", + "post = m5_1.sample_posterior(random.PRNGKey(24071847), p5_1, sample_shape=(1000,))\n", "logprob = log_likelihood(m5_1.model, post, A=d.A.values, D=d.D.values)[\"D\"]\n", "az5_1 = az.from_dict(\n", " posterior={k: v[None, ...] for k, v in post.items()},\n", " log_likelihood={\"D\": logprob[None, ...]},\n", ")\n", - "post = m5_2.sample_posterior(random.PRNGKey(24071847), p5_2, (1000,))\n", + "post = m5_2.sample_posterior(random.PRNGKey(24071847), p5_2, sample_shape=(1000,))\n", "logprob = log_likelihood(m5_2.model, post, M=d.M.values, D=d.D.values)[\"D\"]\n", "az5_2 = az.from_dict(\n", " posterior={k: v[None, ...] for k, v in post.items()},\n", " log_likelihood={\"D\": logprob[None, ...]},\n", ")\n", - "post = m5_3.sample_posterior(random.PRNGKey(24071847), p5_3, (1000,))\n", + "post = m5_3.sample_posterior(random.PRNGKey(24071847), p5_3, sample_shape=(1000,))\n", "logprob = log_likelihood(m5_3.model, post, A=d.A.values, M=d.M.values, D=d.D.values)[\n", " \"D\"\n", "]\n", @@ -1795,7 +1795,7 @@ "metadata": { "anaconda-cloud": {}, "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -1809,7 +1809,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.8" + "version": "3.11.6" } }, "nbformat": 4, diff --git a/notebooks/08_conditional_manatees.ipynb b/notebooks/08_conditional_manatees.ipynb index b1010dd..2efccb2 100644 --- a/notebooks/08_conditional_manatees.ipynb +++ b/notebooks/08_conditional_manatees.ipynb @@ -13,7 +13,7 @@ "metadata": {}, "outputs": [], "source": [ - "!pip install -q numpyro arviz causalgraphicalmodels daft" + "!pip install -q numpyro arviz" ] }, { @@ -254,7 +254,7 @@ } ], "source": [ - "post = m8_1.sample_posterior(random.PRNGKey(1), p8_1, (1000,))\n", + "post = m8_1.sample_posterior(random.PRNGKey(1), p8_1, sample_shape=(1000,))\n", "print_summary({k: v for k, v in post.items() if k != \"mu\"}, 0.89, False)" ] }, @@ -415,12 +415,12 @@ } ], "source": [ - "post = m8_1.sample_posterior(random.PRNGKey(2), p8_1, (1000,))\n", + "post = m8_1.sample_posterior(random.PRNGKey(2), p8_1, sample_shape=(1000,))\n", "logprob = log_likelihood(\n", " m8_1.model, post, rugged_std=dd.rugged_std.values, log_gdp_std=dd.log_gdp_std.values\n", ")\n", "az8_1 = az.from_dict({}, log_likelihood={k: v[None] for k, v in logprob.items()})\n", - "post = m8_2.sample_posterior(random.PRNGKey(2), p8_2, (1000,))\n", + "post = m8_2.sample_posterior(random.PRNGKey(2), p8_2, sample_shape=(1000,))\n", "logprob = log_likelihood(\n", " m8_2.model,\n", " post,\n", @@ -459,7 +459,7 @@ } ], "source": [ - "post = m8_2.sample_posterior(random.PRNGKey(1), p8_2, (1000,))\n", + "post = m8_2.sample_posterior(random.PRNGKey(1), p8_2, sample_shape=(1000,))\n", "print_summary({k: v for k, v in post.items() if k != \"mu\"}, 0.89, False)" ] }, @@ -487,7 +487,7 @@ } ], "source": [ - "post = m8_2.sample_posterior(random.PRNGKey(1), p8_2, (1000,))\n", + "post = m8_2.sample_posterior(random.PRNGKey(1), p8_2, sample_shape=(1000,))\n", "diff_a1_a2 = post[\"a\"][:, 0] - post[\"a\"][:, 1]\n", "jnp.percentile(diff_a1_a2, q=jnp.array([5.5, 94.5]))" ] @@ -592,7 +592,7 @@ } ], "source": [ - "post = m8_3.sample_posterior(random.PRNGKey(1), p8_3, (1000,))\n", + "post = m8_3.sample_posterior(random.PRNGKey(1), p8_3, sample_shape=(1000,))\n", "print_summary({k: v for k, v in post.items() if k != \"mu\"}, 0.89, False)" ] }, @@ -707,12 +707,12 @@ } ], "source": [ - "post = m8_1.sample_posterior(random.PRNGKey(2), p8_1, (1000,))\n", + "post = m8_1.sample_posterior(random.PRNGKey(2), p8_1, sample_shape=(1000,))\n", "logprob = log_likelihood(\n", " m8_1.model, post, rugged_std=dd.rugged_std.values, log_gdp_std=dd.log_gdp_std.values\n", ")\n", "az8_1 = az.from_dict({}, log_likelihood={k: v[None] for k, v in logprob.items()})\n", - "post = m8_2.sample_posterior(random.PRNGKey(2), p8_2, (1000,))\n", + "post = m8_2.sample_posterior(random.PRNGKey(2), p8_2, sample_shape=(1000,))\n", "logprob = log_likelihood(\n", " m8_2.model,\n", " post,\n", @@ -721,7 +721,7 @@ " log_gdp_std=dd.log_gdp_std.values,\n", ")\n", "az8_3 = az.from_dict({}, log_likelihood={k: v[None] for k, v in logprob.items()})\n", - "post = m8_3.sample_posterior(random.PRNGKey(2), p8_3, (1000,))\n", + "post = m8_3.sample_posterior(random.PRNGKey(2), p8_3, sample_shape=(1000,))\n", "logprob = log_likelihood(\n", " m8_3.model,\n", " post,\n", @@ -813,7 +813,7 @@ "outputs": [], "source": [ "rugged_seq = jnp.linspace(start=-0.2, stop=1.2, num=30)\n", - "post = m8_3.sample_posterior(random.PRNGKey(1), p8_3, (1000,))\n", + "post = m8_3.sample_posterior(random.PRNGKey(1), p8_3, sample_shape=(1000,))\n", "predictive = Predictive(m8_3.model, post, return_sites=[\"mu\"])\n", "muA = predictive(random.PRNGKey(2), cid=0, rugged_std=rugged_seq)[\"mu\"]\n", "muN = predictive(random.PRNGKey(2), cid=1, rugged_std=rugged_seq)[\"mu\"]\n", @@ -1129,7 +1129,7 @@ " idx = d.shade_cent == s\n", " ax.scatter(d.water_cent[idx], d.blooms_std[idx])\n", " ax.set(xlim=(-1.1, 1.1), ylim=(-0.1, 1.1), xlabel=\"water\", ylabel=\"blooms\")\n", - " post = m8_4.sample_posterior(random.PRNGKey(1), p8_4, (1000,))\n", + " post = m8_4.sample_posterior(random.PRNGKey(1), p8_4, sample_shape=(1000,))\n", " mu = Predictive(m8_4.model, post, return_sites=[\"mu\"])(\n", " random.PRNGKey(2), shade_cent=s, water_cent=jnp.arange(-1, 2)\n", " )[\"mu\"]\n", @@ -1178,7 +1178,7 @@ "metadata": { "anaconda-cloud": {}, "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -1192,7 +1192,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.8" + "version": "3.11.6" } }, "nbformat": 4, diff --git a/notebooks/09_markov_chain_monte_carlo.ipynb b/notebooks/09_markov_chain_monte_carlo.ipynb index e279e20..b54116f 100644 --- a/notebooks/09_markov_chain_monte_carlo.ipynb +++ b/notebooks/09_markov_chain_monte_carlo.ipynb @@ -13,7 +13,7 @@ "metadata": {}, "outputs": [], "source": [ - "!pip install -q numpyro arviz causalgraphicalmodels daft" + "!pip install -q numpyro arviz" ] }, { @@ -554,7 +554,7 @@ ")\n", "svi_result = svi.run(random.PRNGKey(0), 1000)\n", "p8_3 = svi_result.params\n", - "post = m8_3.sample_posterior(random.PRNGKey(1), p8_3, (1000,))\n", + "post = m8_3.sample_posterior(random.PRNGKey(1), p8_3, sample_shape=(1000,))\n", "print_summary({k: v for k, v in post.items() if k != \"mu\"}, 0.89, False)" ] }, @@ -1490,7 +1490,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.10" + "version": "3.11.6" }, "widgets": { "application/vnd.jupyter.widget-state+json": { diff --git a/notebooks/10_big_entropy_and_the_generalized_linear_model.ipynb b/notebooks/10_big_entropy_and_the_generalized_linear_model.ipynb index 78eb807..27fc0af 100644 --- a/notebooks/10_big_entropy_and_the_generalized_linear_model.ipynb +++ b/notebooks/10_big_entropy_and_the_generalized_linear_model.ipynb @@ -13,7 +13,7 @@ "metadata": {}, "outputs": [], "source": [ - "!pip install -q numpyro arviz causalgraphicalmodels daft" + "!pip install -q numpyro arviz" ] }, { @@ -375,7 +375,7 @@ "metadata": { "anaconda-cloud": {}, "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -389,7 +389,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.8" + "version": "3.11.6" } }, "nbformat": 4, diff --git a/notebooks/11_god_spiked_the_integers.ipynb b/notebooks/11_god_spiked_the_integers.ipynb index adf9abf..614c6ef 100644 --- a/notebooks/11_god_spiked_the_integers.ipynb +++ b/notebooks/11_god_spiked_the_integers.ipynb @@ -13,7 +13,7 @@ "metadata": {}, "outputs": [], "source": [ - "!pip install -q numpyro arviz causalgraphicalmodels daft" + "!pip install -q numpyro arviz" ] }, { @@ -3216,7 +3216,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.10" + "version": "3.11.6" }, "widgets": { "application/vnd.jupyter.widget-state+json": { diff --git a/notebooks/12_monsters_and_mixtures.ipynb b/notebooks/12_monsters_and_mixtures.ipynb index 3dd0841..c82c139 100644 --- a/notebooks/12_monsters_and_mixtures.ipynb +++ b/notebooks/12_monsters_and_mixtures.ipynb @@ -13,7 +13,7 @@ "metadata": {}, "outputs": [], "source": [ - "!pip install -q numpyro arviz causalgraphicalmodels daft" + "!pip install -q numpyro arviz" ] }, { @@ -384,6 +384,13 @@ "m12_2.run(random.PRNGKey(0), **dat2)" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Note:** The results here might be different from the book. There seems to have a bug in R's [dgampois](https://rdrr.io/github/rmcelreath/rethinking/src/R/distributions.r#sym-dgampois) implementation back to the time the book is printed. According to [this issue](https://github.com/rmcelreath/rethinking/issues/260), the bug has been fixed upstream." + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -1832,7 +1839,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.10" + "version": "3.11.6" }, "widgets": { "application/vnd.jupyter.widget-state+json": { diff --git a/notebooks/13_models_with_memory.ipynb b/notebooks/13_models_with_memory.ipynb index ac3c76d..41de64e 100644 --- a/notebooks/13_models_with_memory.ipynb +++ b/notebooks/13_models_with_memory.ipynb @@ -13,7 +13,7 @@ "metadata": {}, "outputs": [], "source": [ - "!pip install -q numpyro arviz causalgraphicalmodels daft" + "!pip install -q numpyro arviz" ] }, { @@ -2398,7 +2398,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.10" + "version": "3.11.6" }, "widgets": { "application/vnd.jupyter.widget-state+json": { diff --git a/notebooks/14_adventures_in_covariance.ipynb b/notebooks/14_adventures_in_covariance.ipynb index 5d99141..f951df9 100644 --- a/notebooks/14_adventures_in_covariance.ipynb +++ b/notebooks/14_adventures_in_covariance.ipynb @@ -13,7 +13,7 @@ "metadata": {}, "outputs": [], "source": [ - "!pip install -q numpyro arviz causalgraphicalmodels daft" + "!pip install -q numpyro arviz networkx" ] }, { @@ -27,9 +27,9 @@ "\n", "import arviz as az\n", "import matplotlib.pyplot as plt\n", + "import networkx as nx\n", "import numpy as np\n", "import pandas as pd\n", - "from causalgraphicalmodels import CausalGraphicalModel\n", "from IPython.display import Image, set_matplotlib_formats\n", "from matplotlib.patches import Ellipse, transforms\n", "\n", @@ -1552,14 +1552,15 @@ } ], "source": [ - "dagIV = CausalGraphicalModel(\n", - " nodes=[\"E\", \"W\", \"U\", \"Q\"], edges=[(\"E\", \"W\"), (\"U\", \"E\"), (\"U\", \"W\"), (\"Q\", \"E\")]\n", - ")\n", - "for s in dagIV.observed_variables:\n", + "dagIV = nx.DiGraph()\n", + "dagIV.add_edges_from([(\"E\", \"W\"), (\"U\", \"E\"), (\"U\", \"W\"), (\"Q\", \"E\")])\n", + "dagIV_do_E = dagIV.copy()\n", + "dagIV_do_E.remove_edges_from(dagIV.in_edges(\"E\"))\n", + "for s in dagIV.nodes:\n", " if s in [\"E\", \"W\"]:\n", " continue\n", - " cond1 = not dagIV.is_d_separated(s, \"E\")\n", - " cond2 = dagIV.do(\"E\").is_d_separated(s, \"W\")\n", + " cond1 = not nx.d_separated(dagIV, {s}, {\"E\"}, {})\n", + " cond2 = nx.d_separated(dagIV_do_E, {s}, {\"W\"}, {})\n", " if cond1 and cond2:\n", " print(s)" ] @@ -1692,6 +1693,16 @@ "m14_7.run(random.PRNGKey(0), **kl_data)" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Note:** The code assumes that the number of households is `kl_dyads.hidB.max()`. A more robust solution would be to set\n", + "```python\n", + "N_households=max(kl_dyads.hidA.max(), kl_dyads.hidB.max())\n", + "```" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -3182,9 +3193,9 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "Python (pydata)", "language": "python", - "name": "python3" + "name": "pydata" }, "language_info": { "codemirror_mode": { @@ -3196,7 +3207,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.10" + "version": "3.10.13" }, "widgets": { "application/vnd.jupyter.widget-state+json": { diff --git a/notebooks/15_missing_data_and_other_opportunities.ipynb b/notebooks/15_missing_data_and_other_opportunities.ipynb index ad0da66..8b062d5 100644 --- a/notebooks/15_missing_data_and_other_opportunities.ipynb +++ b/notebooks/15_missing_data_and_other_opportunities.ipynb @@ -13,7 +13,7 @@ "metadata": {}, "outputs": [], "source": [ - "!pip install -q numpyro arviz causalgraphicalmodels daft" + "!pip install -q numpyro arviz" ] }, { @@ -2123,7 +2123,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.10" + "version": "3.11.6" }, "widgets": { "application/vnd.jupyter.widget-state+json": { diff --git a/notebooks/16_generalized_linear_madness.ipynb b/notebooks/16_generalized_linear_madness.ipynb index 9a83868..6f1df23 100644 --- a/notebooks/16_generalized_linear_madness.ipynb +++ b/notebooks/16_generalized_linear_madness.ipynb @@ -13,7 +13,7 @@ "metadata": {}, "outputs": [], "source": [ - "!pip install -q numpyro arviz causalgraphicalmodels daft" + "!pip install -q numpyro arviz" ] }, { @@ -991,7 +991,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -1005,7 +1005,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.8" + "version": "3.11.6" }, "toc": { "base_numbering": 1, diff --git a/notebooks/17_horoscopes.ipynb b/notebooks/17_horoscopes.ipynb index ebc9e84..3d0c22a 100644 --- a/notebooks/17_horoscopes.ipynb +++ b/notebooks/17_horoscopes.ipynb @@ -17,7 +17,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -31,7 +31,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.8" + "version": "3.11.6" } }, "nbformat": 4, diff --git a/requirements.txt b/requirements.txt index 3a5dcb7..361348c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ numpyro arviz -causalgraphicalmodels daft +networkx \ No newline at end of file From 8bde95c2efdd147f814fd97493196f9bdbd91887 Mon Sep 17 00:00:00 2001 From: Du Phan Date: Wed, 14 Feb 2024 22:57:28 -0500 Subject: [PATCH 02/17] skip deterministic variables in posterior --- notebooks/04_geocentric_models.ipynb | 1 + notebooks/11_god_spiked_the_integers.ipynb | 12 +++++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/notebooks/04_geocentric_models.ipynb b/notebooks/04_geocentric_models.ipynb index 21b472e..8792c8e 100644 --- a/notebooks/04_geocentric_models.ipynb +++ b/notebooks/04_geocentric_models.ipynb @@ -1569,6 +1569,7 @@ "outputs": [], "source": [ "post = m4_3.sample_posterior(random.PRNGKey(1), p4_3, sample_shape=(1000,))\n", + "post.pop(\"mu\")\n", "mu_at_50 = post[\"a\"] + post[\"b\"] * (50 - xbar)" ] }, diff --git a/notebooks/11_god_spiked_the_integers.ipynb b/notebooks/11_god_spiked_the_integers.ipynb index 614c6ef..60a86f7 100644 --- a/notebooks/11_god_spiked_the_integers.ipynb +++ b/notebooks/11_god_spiked_the_integers.ipynb @@ -2444,7 +2444,9 @@ "P_seq = jnp.linspace(-1.4, 3, num=ns)\n", "\n", "# predictions for cid=0 (low contact)\n", - "lambda_ = Predictive(m11_10.sampler.model, m11_10.get_samples())(\n", + "post = m11_10.get_samples()\n", + "post.pop(\"lambda\")\n", + "lambda_ = Predictive(m11_10.sampler.model, post)(\n", " random.PRNGKey(1), P=P_seq, cid=0\n", ")[\"lambda\"]\n", "lmu = jnp.mean(lambda_, 0)\n", @@ -2453,7 +2455,7 @@ "plt.fill_between(P_seq, lci[0], lci[1], color=\"k\", alpha=0.2)\n", "\n", "# predictions for cid=1 (high contact)\n", - "lambda_ = Predictive(m11_10.sampler.model, m11_10.get_samples())(\n", + "lambda_ = Predictive(m11_10.sampler.model, post)(\n", " random.PRNGKey(1), P=P_seq, cid=1\n", ")[\"lambda\"]\n", "lmu = jnp.mean(lambda_, 0)\n", @@ -3202,9 +3204,9 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "Python (pydata)", "language": "python", - "name": "python3" + "name": "pydata" }, "language_info": { "codemirror_mode": { @@ -3216,7 +3218,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.6" + "version": "3.10.13" }, "widgets": { "application/vnd.jupyter.widget-state+json": { From 7dcec40bf3f15f4af80365e140483c652e3a89cb Mon Sep 17 00:00:00 2001 From: Du Phan Date: Thu, 15 Feb 2024 09:22:12 -0500 Subject: [PATCH 03/17] clean kernelspec --- notebooks/04_geocentric_models.ipynb | 2 ++ notebooks/11_god_spiked_the_integers.ipynb | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/notebooks/04_geocentric_models.ipynb b/notebooks/04_geocentric_models.ipynb index 8792c8e..b2d5fda 100644 --- a/notebooks/04_geocentric_models.ipynb +++ b/notebooks/04_geocentric_models.ipynb @@ -1906,6 +1906,7 @@ "outputs": [], "source": [ "post = m4_3.sample_posterior(random.PRNGKey(1), p4_3, sample_shape=(int(1e4),))\n", + "post.pop(\"mu\")\n", "sim_height = Predictive(m4_3.model, post, return_sites=[\"height\"])(\n", " random.PRNGKey(2), weight_seq, None\n", ")[\"height\"]\n", @@ -2147,6 +2148,7 @@ "weight_seq = jnp.linspace(start=-2.2, stop=2, num=30)\n", "pred_dat = {\"weight_s\": weight_seq, \"weight_s2\": weight_seq**2}\n", "post = m4_5.sample_posterior(random.PRNGKey(1), p4_5, sample_shape=(1000,))\n", + "post.pop(\"mu\")\n", "predictive = Predictive(m4_5.model, post)\n", "mu = predictive(random.PRNGKey(2), **pred_dat)[\"mu\"]\n", "mu_mean = jnp.mean(mu, 0)\n", diff --git a/notebooks/11_god_spiked_the_integers.ipynb b/notebooks/11_god_spiked_the_integers.ipynb index 60a86f7..65ab236 100644 --- a/notebooks/11_god_spiked_the_integers.ipynb +++ b/notebooks/11_god_spiked_the_integers.ipynb @@ -3204,9 +3204,9 @@ ], "metadata": { "kernelspec": { - "display_name": "Python (pydata)", + "display_name": "Python 3 (ipykernel)", "language": "python", - "name": "pydata" + "name": "python3" }, "language_info": { "codemirror_mode": { @@ -3218,7 +3218,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.13" + "version": "3.11.6" }, "widgets": { "application/vnd.jupyter.widget-state+json": { From 82a5a20343f05cfcf6a304be05e6b6f887169449 Mon Sep 17 00:00:00 2001 From: Du Phan Date: Thu, 15 Feb 2024 09:24:22 -0500 Subject: [PATCH 04/17] clean kernelspec further --- .../05_the_many_variables_and_the_spurious_waffles.ipynb | 6 +++--- notebooks/06_the_haunted_dag_and_the_causal_terror.ipynb | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/notebooks/05_the_many_variables_and_the_spurious_waffles.ipynb b/notebooks/05_the_many_variables_and_the_spurious_waffles.ipynb index f1bb825..b5bb538 100644 --- a/notebooks/05_the_many_variables_and_the_spurious_waffles.ipynb +++ b/notebooks/05_the_many_variables_and_the_spurious_waffles.ipynb @@ -2141,9 +2141,9 @@ ], "metadata": { "kernelspec": { - "display_name": "Python (pydata)", + "display_name": "Python 3 (ipykernel)", "language": "python", - "name": "pydata" + "name": "python3" }, "language_info": { "codemirror_mode": { @@ -2155,7 +2155,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.13" + "version": "3.11.6" } }, "nbformat": 4, diff --git a/notebooks/06_the_haunted_dag_and_the_causal_terror.ipynb b/notebooks/06_the_haunted_dag_and_the_causal_terror.ipynb index 934b8b1..c6e03e1 100644 --- a/notebooks/06_the_haunted_dag_and_the_causal_terror.ipynb +++ b/notebooks/06_the_haunted_dag_and_the_causal_terror.ipynb @@ -1398,9 +1398,9 @@ ], "metadata": { "kernelspec": { - "display_name": "Python (pydata)", + "display_name": "Python 3 (ipykernel)", "language": "python", - "name": "pydata" + "name": "python3" }, "language_info": { "codemirror_mode": { @@ -1412,7 +1412,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.13" + "version": "3.11.6" } }, "nbformat": 4, From 88c069dbb3f7300e7422d11bc689ad47eacc47a4 Mon Sep 17 00:00:00 2001 From: Du Phan Date: Thu, 15 Feb 2024 09:25:15 -0500 Subject: [PATCH 05/17] clean kernelspec further --- notebooks/14_adventures_in_covariance.ipynb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/notebooks/14_adventures_in_covariance.ipynb b/notebooks/14_adventures_in_covariance.ipynb index f951df9..197aacc 100644 --- a/notebooks/14_adventures_in_covariance.ipynb +++ b/notebooks/14_adventures_in_covariance.ipynb @@ -3193,9 +3193,9 @@ ], "metadata": { "kernelspec": { - "display_name": "Python (pydata)", + "display_name": "Python 3 (ipykernel)", "language": "python", - "name": "pydata" + "name": "python3" }, "language_info": { "codemirror_mode": { @@ -3207,7 +3207,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.13" + "version": "3.11.6" }, "widgets": { "application/vnd.jupyter.widget-state+json": { From bd060bf696baa4e6f9e8ed743db3f6f683ed1fa4 Mon Sep 17 00:00:00 2001 From: Du Phan Date: Thu, 15 Feb 2024 09:40:15 -0500 Subject: [PATCH 06/17] fix workflows --- .github/workflows/main.yml | 13 +++++++++++++ .gitignore | 1 - notebooks/12_monsters_and_mixtures.ipynb | 7 ++++--- 3 files changed, 17 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/main.yml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..fa83b39 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,13 @@ +on: [push] + +jobs: + nikola_build: + runs-on: ubuntu-latest + name: 'Deploy Nikola to GitHub Pages' + steps: + - name: Check out + uses: actions/checkout@v2 + - name: Build and Deploy Nikola + uses: getnikola/nikola-action@v4 + with: + dry_run: false diff --git a/.gitignore b/.gitignore index 691591e..2496af3 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,3 @@ output .doit.db* site/pages/*.ipynb site/listings/*.py - diff --git a/notebooks/12_monsters_and_mixtures.ipynb b/notebooks/12_monsters_and_mixtures.ipynb index c82c139..a51c7c3 100644 --- a/notebooks/12_monsters_and_mixtures.ipynb +++ b/notebooks/12_monsters_and_mixtures.ipynb @@ -1294,7 +1294,9 @@ "kC = 0 # value for contact\n", "kI = jnp.arange(2) # values of intention to calculate over\n", "pdat = dict(A=kA, C=kC, I=kI)\n", - "phi = Predictive(m12_5.sampler.model, m12_5.get_samples())(random.PRNGKey(1), **pdat)[\n", + "post = m12_5.get_samples()\n", + "post.pop(\"phi\")\n", + "phi = Predictive(m12_5.sampler.model, post)(random.PRNGKey(1), **pdat)[\n", " \"phi\"\n", "]" ] @@ -1324,7 +1326,6 @@ } ], "source": [ - "post = m12_5.get_samples()\n", "for s in range(50):\n", " pk = expit(post[\"cutpoints\"][s] - phi[s][..., None])\n", " for i in range(6):\n", @@ -1361,7 +1362,7 @@ "kI = jnp.arange(2) # values of intention to calculate over\n", "pdat = dict(A=kA, C=kC, I=kI)\n", "s = (\n", - " Predictive(m12_5.sampler.model, m12_5.get_samples())(random.PRNGKey(1), **pdat)[\"R\"]\n", + " Predictive(m12_5.sampler.model, post)(random.PRNGKey(1), **pdat)[\"R\"]\n", " + 1\n", ")\n", "plt.hist(s[:, 0], bins=jnp.arange(0.5, 8), rwidth=0.1)\n", From ee25cb93d20ec9ac01c2446ad28d42e9c1268342 Mon Sep 17 00:00:00 2001 From: Du Phan Date: Thu, 15 Feb 2024 11:01:17 -0500 Subject: [PATCH 07/17] fix github action --- .github/workflows/main.yml | 1 + notebooks/04_geocentric_models.ipynb | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index fa83b39..dc815cf 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -8,6 +8,7 @@ jobs: - name: Check out uses: actions/checkout@v2 - name: Build and Deploy Nikola + working-directory: ./site uses: getnikola/nikola-action@v4 with: dry_run: false diff --git a/notebooks/04_geocentric_models.ipynb b/notebooks/04_geocentric_models.ipynb index b2d5fda..984d9e0 100644 --- a/notebooks/04_geocentric_models.ipynb +++ b/notebooks/04_geocentric_models.ipynb @@ -1830,6 +1830,7 @@ } ], "source": [ + "post.pop(\"mu\")\n", "sim_height = Predictive(m4_3.model, post, return_sites=[\"height\"])(\n", " random.PRNGKey(2), weight_seq, None\n", ")[\"height\"]\n", From 812c3035ddf9fa6a8f87d3c3fd6e1c95c9baeb1c Mon Sep 17 00:00:00 2001 From: Du Phan Date: Thu, 15 Feb 2024 11:20:51 -0500 Subject: [PATCH 08/17] remove deterministic in predictive --- .github/workflows/main.yml | 2 +- .../05_the_many_variables_and_the_spurious_waffles.ipynb | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index dc815cf..9c29094 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -8,7 +8,7 @@ jobs: - name: Check out uses: actions/checkout@v2 - name: Build and Deploy Nikola - working-directory: ./site uses: getnikola/nikola-action@v4 with: dry_run: false + working-directory: ./site diff --git a/notebooks/05_the_many_variables_and_the_spurious_waffles.ipynb b/notebooks/05_the_many_variables_and_the_spurious_waffles.ipynb index b5bb538..efbcb50 100644 --- a/notebooks/05_the_many_variables_and_the_spurious_waffles.ipynb +++ b/notebooks/05_the_many_variables_and_the_spurious_waffles.ipynb @@ -192,6 +192,7 @@ "# compute percentile interval of mean\n", "A_seq = jnp.linspace(start=-3, stop=3.2, num=30)\n", "post = m5_1.sample_posterior(random.PRNGKey(1), p5_1, sample_shape=(1000,))\n", + "post.pop(\"mu\")\n", "post_pred = Predictive(m5_1.model, post)(random.PRNGKey(2), A=A_seq)\n", "mu = post_pred[\"mu\"]\n", "mu_mean = jnp.mean(mu, 0)\n", @@ -551,6 +552,7 @@ "outputs": [], "source": [ "post = m5_4.sample_posterior(random.PRNGKey(1), p5_4, sample_shape=(1000,))\n", + "post.pop(\"mu\")\n", "post_pred = Predictive(m5_4.model, post)(random.PRNGKey(2), A=d.A.values)\n", "mu = post_pred[\"mu\"]\n", "mu_mean = jnp.mean(mu, 0)\n", @@ -573,6 +575,7 @@ "# call predictive without specifying new data\n", "# so it uses original data\n", "post = m5_3.sample_posterior(random.PRNGKey(1), p5_3, (int(1e4),))\n", + "post.pop(\"mu\")\n", "post_pred = Predictive(m5_3.model, post)(random.PRNGKey(2), M=d.M.values, A=d.A.values)\n", "mu = post_pred[\"mu\"]\n", "\n", @@ -1394,6 +1397,7 @@ "source": [ "xseq = jnp.linspace(start=dcc.N.min() - 0.15, stop=dcc.N.max() + 0.15, num=30)\n", "post = m5_5.sample_posterior(random.PRNGKey(1), p5_5, sample_shape=(1000,))\n", + "post.pop(\"mu\")\n", "post_pred = Predictive(m5_5.model, post)(random.PRNGKey(2), N=xseq)\n", "mu = post_pred[\"mu\"]\n", "mu_mean = jnp.mean(mu, 0)\n", @@ -1610,6 +1614,7 @@ "source": [ "xseq = jnp.linspace(start=dcc.N.min() - 0.15, stop=dcc.N.max() + 0.15, num=30)\n", "post = m5_7.sample_posterior(random.PRNGKey(1), p5_7, sample_shape=(1000,))\n", + "post.pop(\"mu\")\n", "post_pred = Predictive(m5_7.model, post)(random.PRNGKey(2), M=0, N=xseq)\n", "mu = post_pred[\"mu\"]\n", "mu_mean = jnp.mean(mu, 0)\n", From e8a7736dcfb2e0ca6695f590c8d6449f1f40c839 Mon Sep 17 00:00:00 2001 From: Du Phan Date: Thu, 15 Feb 2024 11:24:00 -0500 Subject: [PATCH 09/17] try different working directory --- .github/workflows/main.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 9c29094..107d174 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -4,6 +4,9 @@ jobs: nikola_build: runs-on: ubuntu-latest name: 'Deploy Nikola to GitHub Pages' + defaults: + run: + working-directory: ./site steps: - name: Check out uses: actions/checkout@v2 @@ -11,4 +14,3 @@ jobs: uses: getnikola/nikola-action@v4 with: dry_run: false - working-directory: ./site From 2dde1c03b184a4e80248c5195f3c1cc1cbb09794 Mon Sep 17 00:00:00 2001 From: Du Phan Date: Thu, 15 Feb 2024 13:17:20 -0500 Subject: [PATCH 10/17] try another working directory --- .github/workflows/main.yml | 4 ++++ .../05_the_many_variables_and_the_spurious_waffles.ipynb | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 107d174..056a14c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,5 +1,9 @@ on: [push] +defaults: + run: + working-directory: ./site + jobs: nikola_build: runs-on: ubuntu-latest diff --git a/notebooks/05_the_many_variables_and_the_spurious_waffles.ipynb b/notebooks/05_the_many_variables_and_the_spurious_waffles.ipynb index efbcb50..6ec678e 100644 --- a/notebooks/05_the_many_variables_and_the_spurious_waffles.ipynb +++ b/notebooks/05_the_many_variables_and_the_spurious_waffles.ipynb @@ -574,7 +574,7 @@ "source": [ "# call predictive without specifying new data\n", "# so it uses original data\n", - "post = m5_3.sample_posterior(random.PRNGKey(1), p5_3, (int(1e4),))\n", + "post = m5_3.sample_posterior(random.PRNGKey(1), p5_3, sample_shape=(int(1e4),))\n", "post.pop(\"mu\")\n", "post_pred = Predictive(m5_3.model, post)(random.PRNGKey(2), M=d.M.values, A=d.A.values)\n", "mu = post_pred[\"mu\"]\n", From 0df6a972ba3531bd096865c24f92bfb84bf23c30 Mon Sep 17 00:00:00 2001 From: Du Phan Date: Thu, 15 Feb 2024 13:31:41 -0500 Subject: [PATCH 11/17] try forking nikola --- .github/workflows/main.yml | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 056a14c..31ffaa0 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,20 +1,13 @@ on: [push] -defaults: - run: - working-directory: ./site - jobs: nikola_build: runs-on: ubuntu-latest name: 'Deploy Nikola to GitHub Pages' - defaults: - run: - working-directory: ./site steps: - name: Check out uses: actions/checkout@v2 - name: Build and Deploy Nikola - uses: getnikola/nikola-action@v4 + uses: fehiepsi/nikola-action@v9 with: dry_run: false From ef3bff9b66a4158180e71c7308b766b5e4fb1536 Mon Sep 17 00:00:00 2001 From: Du Phan Date: Thu, 15 Feb 2024 14:35:04 -0500 Subject: [PATCH 12/17] remove further causalgraphicalmodel code --- ...y_variables_and_the_spurious_waffles.ipynb | 25 ++++++------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/notebooks/05_the_many_variables_and_the_spurious_waffles.ipynb b/notebooks/05_the_many_variables_and_the_spurious_waffles.ipynb index 6ec678e..ae41608 100644 --- a/notebooks/05_the_many_variables_and_the_spurious_waffles.ipynb +++ b/notebooks/05_the_many_variables_and_the_spurious_waffles.ipynb @@ -1690,28 +1690,19 @@ "metadata": {}, "outputs": [], "source": [ - "dag5_7 = CausalGraphicalModel(\n", - " nodes=[\"M\", \"K\", \"N\"], edges=[(\"M\", \"K\"), (\"N\", \"K\"), (\"M\", \"N\")]\n", - ")\n", + "dag5_7 = nx.DiGraph()\n", + "dag5_7.add_edges_from([(\"M\", \"K\"), (\"N\", \"K\"), (\"M\", \"N\")])\n", "coordinates = {\"M\": (0, 0.5), \"K\": (1, 1), \"N\": (2, 0.5)}\n", - "nodes = list(dag5_7.dag.nodes.keys())\n", - "edges = list(dag5_7.dag.edges.keys())\n", "MElist = []\n", "for i in range(2):\n", " for j in range(2):\n", " for k in range(2):\n", - " try:\n", - " new_dag = CausalGraphicalModel(\n", - " nodes=nodes,\n", - " edges=[\n", - " edges[0] if i == 0 else edges[0][::-1],\n", - " edges[1] if j == 0 else edges[1][::-1],\n", - " edges[2] if k == 0 else edges[2][::-1],\n", - " ],\n", - " )\n", - " MElist.append(new_dag)\n", - " except:\n", - " pass" + " new_dag = nx.DiGraph()\n", + " new_dag.add_edges_from(\n", + " [edge[::-1] if flip else edge for edge, flip in zip(dag5_7.edges, (i, j, k))]\n", + " )\n", + " if not list(nx.simple_cycles(new_dag)):\n", + " MElist.append(new_dag)" ] }, { From 9b19138138780d0d854e496a62a7ec0056ab95e2 Mon Sep 17 00:00:00 2001 From: Du Phan Date: Thu, 15 Feb 2024 14:54:37 -0500 Subject: [PATCH 13/17] fix workflows --- .github/workflows/ci.yml | 1 - .github/workflows/main.yml | 28 +++++++++++++++++++++------- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3911e55..1ecd01f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -53,4 +53,3 @@ jobs: - name: Test with nbval run: | find notebooks -maxdepth 1 -name "[01][456789]*.ipynb" | sort -n | xargs pytest -vx --nbval-lax --durations=0 - diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 31ffaa0..81e7130 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,13 +1,27 @@ -on: [push] +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] jobs: nikola_build: - runs-on: ubuntu-latest + name: 'Deploy Nikola to GitHub Pages' + runs-on: ubuntu-latest + strategy: + matrix: + python-version: [3.9] + steps: - - name: Check out - uses: actions/checkout@v2 - - name: Build and Deploy Nikola - uses: fehiepsi/nikola-action@v9 + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 with: - dry_run: false + python-version: ${{ matrix.python-version }} + - name: Build and Deploy Nikola + run: | + python -m pip install --upgrade pip + pip install "Nikola[extras]" + cd site + nikola_github deploy From 6cc9cad03d22ef6e86b280f119808db267ec7dfa Mon Sep 17 00:00:00 2001 From: Du Phan Date: Thu, 15 Feb 2024 15:44:07 -0500 Subject: [PATCH 14/17] fix typo running nikola --- .github/workflows/main.yml | 2 +- notebooks/07_ulysses_compass.ipynb | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 81e7130..7becdb3 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -24,4 +24,4 @@ jobs: python -m pip install --upgrade pip pip install "Nikola[extras]" cd site - nikola_github deploy + nikola github_deploy diff --git a/notebooks/07_ulysses_compass.ipynb b/notebooks/07_ulysses_compass.ipynb index 285fae2..ed0d3f3 100644 --- a/notebooks/07_ulysses_compass.ipynb +++ b/notebooks/07_ulysses_compass.ipynb @@ -444,6 +444,7 @@ ], "source": [ "post = m7_1.sample_posterior(random.PRNGKey(1), p7_1, sample_shape=(1000,))\n", + "post.pop(\"mu\")\n", "mass_seq = jnp.linspace(d.mass_std.min(), d.mass_std.max(), num=100)\n", "l = Predictive(m7_1.model, post, return_sites=[\"mu\"])(\n", " random.PRNGKey(2), mass_std=mass_seq\n", From 7d9295fc24247efae2b0f9b1f69c2debde358674 Mon Sep 17 00:00:00 2001 From: Du Phan Date: Thu, 15 Feb 2024 15:53:36 -0500 Subject: [PATCH 15/17] fix error --- .github/workflows/main.yml | 1 + notebooks/07_ulysses_compass.ipynb | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7becdb3..811c847 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -23,5 +23,6 @@ jobs: run: | python -m pip install --upgrade pip pip install "Nikola[extras]" + git fetch origin gh-pages cd site nikola github_deploy diff --git a/notebooks/07_ulysses_compass.ipynb b/notebooks/07_ulysses_compass.ipynb index ed0d3f3..58f9c8b 100644 --- a/notebooks/07_ulysses_compass.ipynb +++ b/notebooks/07_ulysses_compass.ipynb @@ -563,7 +563,7 @@ } ], "source": [ - "post = m7_1.sample_posterior(random.PRNGKey(1), p7_1, (int(1e4),))\n", + "post = m7_1.sample_posterior(random.PRNGKey(1), p7_1, sample_shape=(int(1e4),))\n", "logprob = log_likelihood(m7_1.model, post, d.mass_std.values, d.brain_std.values)\n", "logprob = logprob[\"brain_std\"]\n", "n = logprob.shape[1]\n", From 46c27e02c4861b3048d1dcfa5d180b0a14a9fad9 Mon Sep 17 00:00:00 2001 From: Du Phan Date: Thu, 15 Feb 2024 20:15:49 -0500 Subject: [PATCH 16/17] fix further issues --- .github/workflows/main.yml | 2 -- notebooks/07_ulysses_compass.ipynb | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 811c847..2cd845d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,8 +1,6 @@ on: push: branches: [ master ] - pull_request: - branches: [ master ] jobs: nikola_build: diff --git a/notebooks/07_ulysses_compass.ipynb b/notebooks/07_ulysses_compass.ipynb index 58f9c8b..faed799 100644 --- a/notebooks/07_ulysses_compass.ipynb +++ b/notebooks/07_ulysses_compass.ipynb @@ -1264,7 +1264,7 @@ ")\n", "az6_7 = az.from_dict({}, log_likelihood={\"h1\": logprob[\"h1\"][None, ...]})\n", "waic_m6_7 = az.waic(az6_7, pointwise=True, scale=\"deviance\")\n", - "post = m6_8.sample_posterior(random.PRNGKey(91), p6_8, (1000,))\n", + "post = m6_8.sample_posterior(random.PRNGKey(91), p6_8, sample_shape=(1000,))\n", "logprob = log_likelihood(\n", " m6_8.model, post, treatment=d.treatment.values, h0=d.h0.values, h1=d.h1.values\n", ")\n", From 7de912d87650d9f30a80667a07f966d4acbfd644 Mon Sep 17 00:00:00 2001 From: Du Phan Date: Thu, 15 Feb 2024 21:03:02 -0500 Subject: [PATCH 17/17] fix chapter 8 --- notebooks/08_conditional_manatees.ipynb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/notebooks/08_conditional_manatees.ipynb b/notebooks/08_conditional_manatees.ipynb index 2efccb2..b0f727d 100644 --- a/notebooks/08_conditional_manatees.ipynb +++ b/notebooks/08_conditional_manatees.ipynb @@ -508,6 +508,7 @@ "rugged_seq = jnp.linspace(start=-1, stop=1.1, num=30)\n", "\n", "# compute mu over samples, fixing cid=1\n", + "post.pop(\"mu\")\n", "predictive = Predictive(m8_2.model, post, return_sites=[\"mu\"])\n", "mu_NotAfrica = predictive(random.PRNGKey(2), cid=1, rugged_std=rugged_seq)[\"mu\"]\n", "\n", @@ -814,6 +815,7 @@ "source": [ "rugged_seq = jnp.linspace(start=-0.2, stop=1.2, num=30)\n", "post = m8_3.sample_posterior(random.PRNGKey(1), p8_3, sample_shape=(1000,))\n", + "post.pop(\"mu\")\n", "predictive = Predictive(m8_3.model, post, return_sites=[\"mu\"])\n", "muA = predictive(random.PRNGKey(2), cid=0, rugged_std=rugged_seq)[\"mu\"]\n", "muN = predictive(random.PRNGKey(2), cid=1, rugged_std=rugged_seq)[\"mu\"]\n", @@ -1130,6 +1132,7 @@ " ax.scatter(d.water_cent[idx], d.blooms_std[idx])\n", " ax.set(xlim=(-1.1, 1.1), ylim=(-0.1, 1.1), xlabel=\"water\", ylabel=\"blooms\")\n", " post = m8_4.sample_posterior(random.PRNGKey(1), p8_4, sample_shape=(1000,))\n", + " post.pop(\"mu\")\n", " mu = Predictive(m8_4.model, post, return_sites=[\"mu\"])(\n", " random.PRNGKey(2), shade_cent=s, water_cent=jnp.arange(-1, 2)\n", " )[\"mu\"]\n",