{
"cells": [
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"# Learning a CStree"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This notebook shows how to learn a CStree from observational data using an exhaustive search procedure. "
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"The autoreload extension is already loaded. To reload it, use:\n",
" %reload_ext autoreload\n"
]
}
],
"source": [
"import numpy as np\n",
"import networkx as nx\n",
"\n",
"import cslearn.cstree as ct\n",
"import cslearn.stage as st\n",
"import cslearn.learning as ctl\n",
"import cslearn.scoring as sc\n",
"\n",
"%load_ext autoreload\n",
"%autoreload 2"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"## Create a CStree"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We first create a CStree which we know can be represented by a single DAG, shown below. We sample the stage probabilities from the Beta distribution with total pseudo counts 1."
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n",
"\n",
"\n"
],
"text/plain": [
">"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.random.seed(5)\n",
"tree = ct.CStree([2] * 3, labels=[\"a\", \"b\", \"c\"])\n",
"\n",
"tree.update_stages(\n",
" {\n",
" 0: [{\"context\": {0: 0}}, {\"context\": {0: 1}}],\n",
" 1: [{\"context\": {1: 0}}, {\"context\": {1: 1}}],\n",
" }\n",
")\n",
"\n",
"tree.sample_stage_parameters(alpha=1.0)\n",
"tree.plot(full=True)"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Number of DAGs: 1\n",
"Context: None\n"
]
},
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n",
"\n",
"\n"
],
"text/plain": [
">"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"true_adags = tree.to_minimal_context_agraphs()\n",
"print(\"Number of DAGs:\", len(true_adags))\n",
"print(\"Context:\", list(true_adags.keys())[0])\n",
"list(true_adags.values())[0]"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"## Draw samples"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We draw 10000 samples from this CStree."
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [],
"source": [
"df = tree.sample(10000)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Calculate score tables"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The structure learning (learning of CStree) uses pre-calculated scores. We restrict the number of variables in each context to be at most 2 and use the BDeu score with pseudo count 1. By letting poss_cvars=None, the possible context variables for a variable are unrestricted."
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"Context score tables: 100%|██████████| 3/3 [00:00<00:00, 160.33it/s]\n",
"Creating #stagings tables: 100%|██████████| 3/3 [00:00<00:00, 2533.81it/s]\n",
"Order score tables: 100%|██████████| 3/3 [00:00<00:00, 2697.88it/s]\n"
]
}
],
"source": [
"score_table, context_scores, _ = sc.order_score_tables(\n",
" df, max_cvars=2, poss_cvars=None, alpha_tot=1.0, method=\"BDeu\"\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The dict score_table contains the order score tables and context_scores, the scores for every context of every variable. "
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"## Find the optimal order by exhaustive search"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We first find the optimal order using an exhaustive search."
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"optimal order: ['b', 'c', 'a'], score -16332.559328979401\n"
]
}
],
"source": [
"optord, score = ctl._find_optimal_order(score_table)\n",
"print(\"optimal order: {}, score {}\".format(optord, score))"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"## Find the optimal CStree (staging of each level) of the best order"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Given the optimal order, we find the optomial CStree consistent with this order."
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [],
"source": [
"opttree = ctl._optimal_cstree_given_order(optord, context_scores)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We plot the tree before estimating the parameters."
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n",
"\n",
"\n"
],
"text/plain": [
">"
]
},
"execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"opttree.plot(full=True)"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"## Estimate the parameters"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Estimate the stage parameters using the BDeu prior with a total pseudo count per level of 1."
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n",
"\n",
"\n"
],
"text/plain": [
">"
]
},
"execution_count": 20,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"opttree.estimate_stage_parameters(df, alpha_tot=1.0, method=\"BDeu\")\n",
"opttree.plot(full=True)"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"## Plot the minimal context DAGs"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Number of DAGs: 1\n",
"Context: None\n"
]
},
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n",
"\n",
"\n"
],
"text/plain": [
">"
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"opt_adags = opttree.to_minimal_context_agraphs()\n",
"print(\"Number of DAGs:\", len(opt_adags))\n",
"print(\"Context:\", list(opt_adags.keys())[0])\n",
"list(opt_adags.values())[0]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Note that this has the same CSI/CI statement as the original DAG representation."
]
}
],
"metadata": {
"kernelspec": {
"display_name": "cstree_env",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.3"
},
"orig_nbformat": 4
},
"nbformat": 4,
"nbformat_minor": 2
}