{ "cells": [ { "cell_type": "markdown", "id": "pairwise-0", "metadata": {}, "source": "# Pairwise direction (ANM / PNL)\n\n[](https://colab.research.google.com/github/Abel-ai-lab/andrey/blob/main/examples/pairwise.ipynb) {download}`Download this notebook <../../../examples/pairwise.ipynb>`\n\nANM and PNL take two variables and test which one causes the other. Each fits a model in both\ndirections and tests whether the estimated noise is independent of the proposed cause, which holds\nonly in the causal direction. ANM fits an additive noise model, `y = f(x) + e`; PNL fits a\npost-nonlinear one, `y = f2(f1(x) + e)`. Both return a two-node DAG and both directions' p-values." }, { "cell_type": "markdown", "id": "pairwise-1", "metadata": {}, "source": [ "## Start\n", "\n", "Choose a CPU runtime and run this cell first. In Colab it installs `andrey-core==0.9.0` from PyPI;\n", "local kernels use the installed environment." ] }, { "cell_type": "code", "execution_count": 1, "id": "pairwise-2", "metadata": { "tags": [ "colab-setup" ] }, "outputs": [], "source": [ "import os\n", "import sys\n", "\n", "IN_COLAB = \"google.colab\" in sys.modules\n", "\n", "if IN_COLAB:\n", " os.environ[\"ANDREY_DEVICE\"] = \"cpu\"\n", " !pip install --quiet \"andrey-core[viz]==0.9.0\" pandas" ] }, { "cell_type": "code", "execution_count": 2, "id": "pairwise-3", "metadata": {}, "outputs": [], "source": [ "import pandas as pd\n", "from IPython.display import display\n", "\n", "import andrey\n", "import andrey.viz\n", "from andrey.data import sample_scm" ] }, { "cell_type": "markdown", "id": "pairwise-4", "metadata": {}, "source": [ "## Data\n", "\n", "`sample_scm` draws a cause-effect pair: two variables and one edge, in a direction the seed draws.\n", "Here the effect is a post-nonlinear function of the cause with Laplace noise, 500 samples." ] }, { "cell_type": "code", "execution_count": 3, "id": "pairwise-5", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "500 observations of 2 variables, seed 3\n" ] }, { "data": { "text/html": [ "" ], "text/plain": [ "''" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "seed = 3\n", "pair = sample_scm(\n", " graph=\"erdos_renyi\",\n", " functional=\"post_nonlinear\",\n", " noise=\"laplace\",\n", " d=2,\n", " n=500,\n", " seed=seed,\n", " scale=\"standardize\",\n", " density=1.0,\n", ")\n", "X, truth = pair.data, pair.graph\n", "print(f\"{X.shape[0]} observations of 2 variables, seed {seed}\")\n", "display(andrey.viz.draw(truth))" ] }, { "cell_type": "markdown", "id": "pairwise-6", "metadata": {}, "source": [ "## Fit ANM and PNL\n", "\n", "Column 0 is `x` and column 1 is `y`. `pval_forward` tests `x -> y` and `pval_backward` tests\n", "`y -> x`; by default the edge points in the direction with the larger p-value. Pass a significance\n", "level such as `alpha=0.05` to draw an edge only when exactly one direction's p-value is above it." ] }, { "cell_type": "code", "execution_count": 4, "id": "pairwise-7", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "ANM dag | 2 nodes | 1 edges (1 directed)\n", "\n", " 1 -> 0\n", "\n", " pval_forward: 9.834e-13\n", " pval_backward: 0.0021\n", " stat_forward: 5.487\n", " stat_backward: 2.195\n", "\n", "PNL dag | 2 nodes | 1 edges (1 directed)\n", "\n", " 1 -> 0\n", "\n", " pval_forward: 0.0001507\n", " pval_backward: 0.01781\n", " stat_forward: 2.71\n", " stat_backward: 1.811\n" ] } ], "source": [ "print(andrey.anm(X), end=\"\\n\\n\")\n", "print(andrey.pnl(X))" ] }, { "cell_type": "markdown", "id": "pairwise-8", "metadata": {}, "source": [ "## Compare over ten pairs\n", "\n", "Each method runs on the pairs its model describes: ANM on additive-noise pairs with Gaussian noise,\n", "and PNL on post-nonlinear pairs with Laplace noise. One pair can favor either answer, so the table\n", "covers ten seeds." ] }, { "cell_type": "code", "execution_count": 5, "id": "pairwise-9", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
| \n", " | ANM | \n", "PNL | \n", "
|---|---|---|
| seed | \n", "\n", " | \n", " |
| 0 | \n", "true direction | \n", "true direction | \n", "
| 1 | \n", "true direction | \n", "true direction | \n", "
| 2 | \n", "true direction | \n", "true direction | \n", "
| 3 | \n", "true direction | \n", "true direction | \n", "
| 4 | \n", "true direction | \n", "true direction | \n", "
| 5 | \n", "reversed | \n", "true direction | \n", "
| 6 | \n", "true direction | \n", "true direction | \n", "
| 7 | \n", "true direction | \n", "true direction | \n", "
| 8 | \n", "reversed | \n", "true direction | \n", "
| 9 | \n", "true direction | \n", "true direction | \n", "