Skip to content

Commit 8b7f6e7

Browse files
committed
small changes to poisson_line_process.ipynb
1 parent 2e8f21f commit 8b7f6e7

File tree

1 file changed

+64
-31
lines changed

1 file changed

+64
-31
lines changed

examples/poisson-line-process/poisson_line_process.ipynb

Lines changed: 64 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,23 @@
1919
"id": "56965fba-b90b-4233-a819-bb747ecd9d81",
2020
"metadata": {},
2121
"source": [
22-
"# Poisson Line Process Case Study: Statistical Metamorphic Testing"
22+
"# Poisson Line Process Tutorial: Statistical Metamorphic Testing"
23+
]
24+
},
25+
{
26+
"cell_type": "markdown",
27+
"id": "5adf7cdc-fd96-47a4-a194-f1f060a4c0c5",
28+
"metadata": {},
29+
"source": [
30+
"## Overview"
2331
]
2432
},
2533
{
2634
"cell_type": "markdown",
2735
"id": "5b5f1661-9d24-43e3-88ee-add75b744e87",
2836
"metadata": {},
2937
"source": [
30-
"## Overview\n",
31-
"In this tutorial, we demonstrate using the **core Python API** how the Causal Testing Framework (CTF) can be employed to implement statistical metamorphic testing. Broadly speaking, this example involves running a series of causal test cases that incrementally change the width and height of the sampling window of a Poisson Line Tessellation (PLT) model. We then show how statistical estimation can produce similar results using only a fraction of the data. Further details on the methodology can be found in Section 5.1 of our [paper](https://dl.acm.org/doi/10.1145/3607184)."
38+
"The purpose of this tutorial is to use the Causal Testing Framework's **core Python API** to demonstrate how it can be employed to implement statistical metamorphic testing. More specifically, this example involves running a series of causal test cases that incrementally change the width and height of the sampling window of a Poisson Line Tessellation (PLT) model. Further details on the methodology can be found in Section 5.1 of our [paper](https://dl.acm.org/doi/10.1145/3607184) and additional resources for this tutorial can be found at the end of this notebook."
3239
]
3340
},
3441
{
@@ -38,7 +45,7 @@
3845
"source": [
3946
"### Step 1: Defining your Input Configurations\n",
4047
"\n",
41-
"A good first step is to define your file paths, including your input configurations:"
48+
"Before diving into the details, a good first step is to define your file paths, including your input configurations:"
4249
]
4350
},
4451
{
@@ -80,7 +87,9 @@
8087
"\n",
8188
"- `Meta` variables, which are not directly observable but can be related to the system.\n",
8289
"\n",
83-
"Secondly, the causal DAG encodes information about the expected causal structure of the system through nodes representing variables and directed edges representing causal relationships, which is a model of how the data could have been generated. Together, the Causal DAG and modelling scenario form the `Causal Specification`."
90+
"Secondly, the causal DAG encodes information about the expected causal structure of the system through nodes representing variables and directed edges representing causal relationships, which is a model of how the data could have been generated. Together, the Causal DAG and modelling scenario form the `Causal Specification`.\n",
91+
"\n",
92+
"**Note**: The CTF doesn't support native visualisation tools, but it is possible to use existing frameworks such as NetworkX to visualise your DAG. Alternatively, browser-based environments such as [DAGitty](https://www.dagitty.net/) may also be useful."
8493
]
8594
},
8695
{
@@ -96,12 +105,12 @@
96105
"id": "40f85921-40b7-46e5-aede-606900582f4b",
97106
"metadata": {},
98107
"source": [
99-
"At this point, it might be worthwhile to interrogate your data and apply any pre-processing, transforming or cleaning as necessary. However, for the purposes of this example, there won't be any additional processing required. Section 5.13 of the paper explains how this dataset was generated."
108+
"At this point, it might be worthwhile to interrogate your data and apply any pre-processing, transforming or cleaning as necessary. However, for the purposes of this tutorial, there won't be any additional processing required. Section 5.13 of our [paper](https://dl.acm.org/doi/10.1145/3607184) explains in detail how this dataset was generated."
100109
]
101110
},
102111
{
103112
"cell_type": "code",
104-
"execution_count": 2,
113+
"execution_count": 3,
105114
"id": "d7d27532-7995-4d76-b40e-e6ae9e7cc645",
106115
"metadata": {},
107116
"outputs": [
@@ -281,7 +290,7 @@
281290
"[1000 rows x 7 columns]"
282291
]
283292
},
284-
"execution_count": 2,
293+
"execution_count": 3,
285294
"metadata": {},
286295
"output_type": "execute_result"
287296
}
@@ -304,7 +313,7 @@
304313
},
305314
{
306315
"cell_type": "code",
307-
"execution_count": 3,
316+
"execution_count": 4,
308317
"id": "ac297d2d-5a2f-4c33-bbdc-967d54e24e3f",
309318
"metadata": {},
310319
"outputs": [],
@@ -352,18 +361,24 @@
352361
"causal_specification = CausalSpecification(scenario, causal_dag) "
353362
]
354363
},
364+
{
365+
"cell_type": "markdown",
366+
"id": "877d413d-ff96-4481-953f-891c19493531",
367+
"metadata": {},
368+
"source": [
369+
"### Step 3: Create Causal Test Cases"
370+
]
371+
},
355372
{
356373
"cell_type": "markdown",
357374
"id": "be854667-44de-4f40-a37d-fb35588f047a",
358375
"metadata": {},
359376
"source": [
360-
"### Step 3: Create a Causal Test Case\n",
361-
" \n",
362377
"Now that we've created our Causal Specification, we're ready to create our Causal Tests. Causal tests are essentially metamorphic tests that are executed using statistical causal inference. A causal test expresses the change in a given output that we expect to see when we change a particular input in some way. \n",
363378
"\n",
364379
"Firstly, a `base test case`, which specifies the relationship between the given output and input and the desired effect, is required to build a `causal test case`. Together, the causal test case forms the complete executable test, which is the minimum required to perform identification on the DAG.\n",
365380
"\n",
366-
"The two metamorphic relations we would like to investigate are the following:\n",
381+
"In this tutorial, the two metamorphic relations we would like to investigate are the following:\n",
367382
"\n",
368383
"1. Doubling the intensity should cause the number of polygons per unit area to increase by a factor of 4.\n",
369384
"2. The number of polygons per unit area should be independent of width and height."
@@ -379,7 +394,7 @@
379394
},
380395
{
381396
"cell_type": "code",
382-
"execution_count": 4,
397+
"execution_count": 5,
383398
"id": "9b8491ab-0a90-4061-baee-8e1ecef7371d",
384399
"metadata": {},
385400
"outputs": [],
@@ -400,24 +415,24 @@
400415
"id": "e8026067-4df6-43f4-8927-6ac9415b9232",
401416
"metadata": {},
402417
"source": [
403-
"Following this, we can now create our causal test case. The minimum parameter's well need to create this are: the expected causal effect as a `CausalEffect` object (e.g. `ExactValue`), the estimate type, which is a `str` specifying the type of estimate to return, and an estimator, which can be is an `Estimator` object. Note, since the relation we're investigating is inherently linear, we can use the `LinearRegressionEstimator` class to build our causal test case."
418+
"Following this, we can now create our causal test case. The minimum parameter's well need to create this are: the expected causal effect as a `CausalEffect` object (e.g. `ExactValue`), the estimate type, which is a `str` specifying the type of estimate to return, and an estimator, which can be is an `Estimator` object. Since the relation we're investigating is inherently linear, we can use the `LinearRegressionEstimator` class to build our causal test case."
404419
]
405420
},
406421
{
407422
"cell_type": "code",
408-
"execution_count": 5,
423+
"execution_count": 6,
409424
"id": "fa53a888-68e1-4f6f-babf-16d3a206ea49",
410425
"metadata": {},
411426
"outputs": [],
412427
"source": [
413428
"import numpy as np\n",
414429
"from causal_testing.estimation.linear_regression_estimator import LinearRegressionEstimator\n",
415430
"\n",
416-
"control_values, treatment_values = 2 ** np.arange(0, 4), 2 ** np.arange(1, 5)\n",
431+
"control_values, treatment_values = 2 ** np.arange(0, 4), 2 ** np.arange(1, 5) # Initialise the dummy intensity variables\n",
417432
"\n",
418-
"intensity_results = []\n",
433+
"intensity_results = [] # Initiate an empty list to store the causal test results\n",
419434
"\n",
420-
"for (control, treatment) in zip(control_values, treatment_values):\n",
435+
"for (control, treatment) in zip(control_values, treatment_values): # Simultaneously loop over control and treatment\n",
421436
" \n",
422437
" estimator=LinearRegressionEstimator(\n",
423438
" df=df, # Pass in the dataframe\n",
@@ -453,12 +468,12 @@
453468
"id": "d6793dc5-6425-4722-b430-f57aaf3fd181",
454469
"metadata": {},
455470
"source": [
456-
"Finally, we can parse the causal test results as a `pandas` dataframe and export it to a `.csv` file."
471+
"Finally, we can parse the causal test results as a `pandas` dataframe and optionally export it to a `.csv` file."
457472
]
458473
},
459474
{
460475
"cell_type": "code",
461-
"execution_count": 6,
476+
"execution_count": 7,
462477
"id": "6bc8be40-bc95-4187-8771-4ce096acc7b5",
463478
"metadata": {},
464479
"outputs": [
@@ -535,7 +550,7 @@
535550
"3 8 16 8 16 3.699311"
536551
]
537552
},
538-
"execution_count": 6,
553+
"execution_count": 7,
539554
"metadata": {},
540555
"output_type": "execute_result"
541556
}
@@ -548,12 +563,20 @@
548563
"# intensity_results_df.to_csv(\"intensity_test_results.csv\", index=0) # Uncomment this to save as a csv."
549564
]
550565
},
566+
{
567+
"cell_type": "markdown",
568+
"id": "f8ad21d8-6451-4f6c-a69d-cb939ea4f96b",
569+
"metadata": {},
570+
"source": [
571+
"### Summary"
572+
]
573+
},
551574
{
552575
"cell_type": "markdown",
553576
"id": "e62216b2-60ed-49b7-a2eb-0ad755bd91fc",
554577
"metadata": {},
555578
"source": [
556-
"From the above causal test results and the risk ratios, we can conclude that doubling the intensity **does not** cause the number of polygons per unit area to increase by a factor of 4 as we expected - but by factors ranging from 2.8 - 3.7."
579+
"From the above causal test results and the risk ratios, we can conclude that doubling the intensity **does not** cause the number of polygons per unit area to increase by a factor of 4 as we expected - but by factors ranging from 2.8 - 3.7, meaning that the metamorphic relation is not satisfied. This is a significant result since our hypothesis was that "
557580
]
558581
},
559582
{
@@ -571,23 +594,23 @@
571594
"source": [
572595
"In a very similar way to the method above, we can test our second metamorphic relation that the number of polygons per unit area should be independent of sample width and height. Since we are only interested in whether there is some effect, we use the average treatment effect (ATE) instead of the risk ratio from above, which quantifies the additive change in outcome caused by the intervention.\n",
573596
"\n",
574-
"To investigate whether the width affects number of polygons per unit area, we need to execute a new set of test cases, but this time fixing the intensity and varying the width. Note: we don't need to redefine the causal specification, nor the perform identification again; but we have to redefine our base test case."
597+
"To investigate whether the width affects number of polygons per unit area, we need to execute a new set of test cases, but this time fixing the intensity and varying the width. Note: we don't need to redefine the causal specification, nor the perform identification again; but we have to redefine our base test case since we're now considering the Polygon's width as the treatment variable."
575598
]
576599
},
577600
{
578601
"cell_type": "code",
579-
"execution_count": 7,
602+
"execution_count": 8,
580603
"id": "67bf5061-720f-4b3a-a371-3ff3092e81e1",
581604
"metadata": {},
582605
"outputs": [],
583606
"source": [
584-
"control_values, treatment_values = np.arange(1,10), np.arange(1, 17)\n",
607+
"control_values, treatment_values = np.arange(1,10), np.arange(1, 17) # Initialise the dummy width variables\n",
585608
"\n",
586-
"width_results = [] # Empty list for storing test case results\n",
609+
"width_results = [] # Empty list for storing test case results \n",
587610
"\n",
588611
"base_test_case = BaseTestCase(treatment_variable=width, outcome_variable=num_shapes_unit) # Create the base test case\n",
589612
"\n",
590-
"adjustment_set = causal_specification.causal_dag.identification(base_test_case)\n",
613+
"adjustment_set = causal_specification.causal_dag.identification(base_test_case) # Calculate the adjustment set again (if it exists)\n",
591614
"\n",
592615
"for intensity in treatment_values:\n",
593616
" \n",
@@ -626,7 +649,7 @@
626649
},
627650
{
628651
"cell_type": "code",
629-
"execution_count": 12,
652+
"execution_count": 9,
630653
"id": "6c54392c-4e6b-42b3-b39a-e0d1d0ab25b7",
631654
"metadata": {},
632655
"outputs": [
@@ -768,7 +791,7 @@
768791
"9 1.0 2.0 2 -7.378642 -16.381136 1.623851"
769792
]
770793
},
771-
"execution_count": 12,
794+
"execution_count": 9,
772795
"metadata": {},
773796
"output_type": "execute_result"
774797
}
@@ -779,20 +802,30 @@
779802
"width_results_df.head(10)"
780803
]
781804
},
805+
{
806+
"cell_type": "markdown",
807+
"id": "8c085e53-a56e-4f4a-b273-e6af46beba72",
808+
"metadata": {},
809+
"source": [
810+
"### Summary"
811+
]
812+
},
782813
{
783814
"cell_type": "markdown",
784815
"id": "7fcfe837-5d71-4603-b8a5-d3e3f50ceccc",
785816
"metadata": {},
786817
"source": [
787-
"The causal test results in this case demonstrate that the ATE values for width increases from 1 → 2 through 9 → 10, revealing that while most changes produce non-significant effects (ATEs ranging from -2.7097 to -0.5308 with confidence intervals containing zero), the width change from 1 → 2 produces a statistically significant negative effect of -7.3786 with a confidence interval of [-13.9182, -0.8390]. This either indicates there is a problem with either the program, or the metamorphic property itself. A likely interpretation is that, geometrically, lines are less likely to intersect a smaller sample window. As the sample window becomes larger, there is more area to average over. Therefore, the metamorphic relations should ideally specify a minimum window size to which they apply."
818+
"The causal test results in this case demonstrate that the ATE values for width increases from `1 → 2` through `9 → 10`, revealing that while most changes produce non-significant effects (ATEs ranging from `-2.7097` to `-0.5308` with confidence intervals containing zero), the width change from `1 → 2` produces a statistically significant negative effect of `-7.3786` with a confidence interval of `[-13.9182, -0.8390]`. This either indicates there is a problem with either the program, or the metamorphic property itself. A likely interpretation is that, geometrically, lines are less likely to intersect a smaller sample window. As the sample window becomes larger, there is more area to average over. Therefore, the metamorphic relations should ideally specify a minimum window size to which they apply.\n",
819+
"\n",
820+
"Additionally, in the paper we further demonstrate that these results show that the CTF was able to identify the same discrepancy as conventional statistical metamorphic testing, but using only a fifth of the data. Ultimately, this highlights the potential of causal inference-driven approaches to offer economical alternatives to testing techniques that depend on repeated potentially costly executions of the system under test."
788821
]
789822
},
790823
{
791824
"cell_type": "markdown",
792825
"id": "41545617-60e9-468d-a356-9dc1f433953d",
793826
"metadata": {},
794827
"source": [
795-
"# Resources"
828+
"## Additional Resources"
796829
]
797830
},
798831
{

0 commit comments

Comments
 (0)