Description
This is a short tutorial of DAGitty. We will focus on the basics of drawing DAGs and performing graphical analyses on DAGs. DAGitty covers more useful functioning than what is introduced here. For more details, please visit http://www.dagitty.net.
# please download and load dagitty to the workspace.
require(dagitty)
## Loading required package: dagitty
## Warning: package 'dagitty' was built under R version 4.0.5
The Basics
You may draw a DAG with a simple symbolic language used by DAGitty. To draw a DAG, you may use statement like: ‘dag{…}’, and within the curly brackets, you need to specify nodes (variables) and links. For nodes, use a statement like ‘X[…]’, and within the brackets, you specify properties such as positions (‘pos = …’). For links, you specify the links between nodes, such as ‘X -> Y’. Note that you may also specify the paths to make things easier.
# Note that you may also use different paths statements for the same DAG, as long as all links are included.
g <- dagitty('dag {
X [pos="0,1"]
T [pos="1,2"]
Z [pos="2,2"]
W [pos="1,0"]
Y [pos="2,1"]
X -> T <- Z -> Y
X <- W -> T -> Y
W -> Z
X-> Y
}')
plot(g)
Given the DAG, you may request a bunch of things, such as parents, children, ancestors and descendants of nodes.
#By convention, descendants(g,v) and ancestors(g,v) include v but children(g,v) and parents(g,v) do not.
parents(g,"Z") # parents of Z
## [1] "W"
ancestors(g,"Z") # ancestors of Z
## [1] "Z" "W"
children(g,"W") #children of W
## [1] "T" "X" "Z"
descendants(g,"W") #descendants of W
## [1] "W" "Z" "Y" "X" "T"
Path Analysis
Furthermore, you can analyze the paths between any pair of nodes using paths(). The function returns a list with the first element showing all paths and the second whether paths are open (i.e., d-separated).
#all paths between X and Y
paths(g,"X","Y")
## $paths
## [1] "X -> T -> Y" "X -> T <- W -> Z -> Y" "X -> T <- Z -> Y"
## [4] "X -> Y" "X <- W -> T -> Y" "X <- W -> T <- Z -> Y"
## [7] "X <- W -> Z -> T -> Y" "X <- W -> Z -> Y"
##
## $open
## [1] TRUE FALSE FALSE TRUE TRUE FALSE TRUE TRUE
You can also test if conditioning on some variables d-separates a pair of nodes by using dseparated.
nodes <- c("W","Y")
if(dseparated(g,"X","Z",nodes)){
message("X"," and ", "Y"," are independent.")
} else {
message("X"," and ", "Y", " are not independent.")
}
## X and Y are not independent.
As a matter of fact, you may also get all implied independencies in the graph with the function below:
impliedConditionalIndependencies(g)
## W _||_ Y | T, X, Z
## X _||_ Z | W
Adjustment Sets
Given a DAG, the package also gives suggestions of the set of variables for adjustments for the identification of a causal effect. This function makes use of the do-calculus.
#To get all sets of variables for backdoor adjustments
print("All adjustment sets")
## [1] "All adjustment sets"
adjustmentSets(g,"X","Y",type = "all")
## { W }
## { W, Z }
#The minimal set if "type" is not specified
print("The minimal adjustment set")
## [1] "The minimal adjustment set"
adjustmentSets(g,"X","Y")
## { W }
You may also test if including a node in the adjustment set is valid.
#set the cause and outcome variable
exposures(g) <- "X"
outcomes(g) <- "Y"
#checking if including T is Okay
isAdjustmentSet(g,"T")
## [1] FALSE
LS0tDQp0aXRsZTogJ1R1dG9yaWFsIDE6IERyYXdpbmcgYW5kIGFuYWx5emluZyBEQUdzIHdpdGggREFHaXR0eScNCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICBkZl9wcmludDogdGliYmxlDQogICAgY29kZV9kb3dubG9hZDogeWVzDQogICAgdGhlbWU6IGNlcnVsZWFuDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZmxvYXQ6IHllcw0KICAgIG51bWJlcl9zZWN0aW9uczogbm8NCiAgcGRmX2RvY3VtZW50Og0KICAgIHRvYzogeWVzDQotLS0NCg0KIyMjICoqRGVzY3JpcHRpb24qKg0KVGhpcyBpcyBhIHNob3J0IHR1dG9yaWFsIG9mIERBR2l0dHkuIFdlIHdpbGwgZm9jdXMgb24gdGhlIGJhc2ljcyBvZiBkcmF3aW5nIERBR3MgYW5kIHBlcmZvcm1pbmcgZ3JhcGhpY2FsIGFuYWx5c2VzIG9uIERBR3MuIERBR2l0dHkgY292ZXJzIG1vcmUgdXNlZnVsIGZ1bmN0aW9uaW5nIHRoYW4gd2hhdCBpcyBpbnRyb2R1Y2VkIGhlcmUuIEZvciBtb3JlIGRldGFpbHMsIHBsZWFzZSB2aXNpdCBodHRwOi8vd3d3LmRhZ2l0dHkubmV0Lg0KDQpgYGB7cn0NCiMgcGxlYXNlIGRvd25sb2FkIGFuZCBsb2FkIGRhZ2l0dHkgdG8gdGhlIHdvcmtzcGFjZS4gDQpyZXF1aXJlKGRhZ2l0dHkpDQpgYGANCg0KIyMjIFRoZSBCYXNpY3MNCllvdSBtYXkgZHJhdyBhIERBRyB3aXRoIGEgc2ltcGxlIHN5bWJvbGljIGxhbmd1YWdlIHVzZWQgYnkgREFHaXR0eS4gVG8gZHJhdyBhIERBRywgeW91IG1heSB1c2Ugc3RhdGVtZW50IGxpa2U6ICdkYWd7Li4ufScsIGFuZCB3aXRoaW4gdGhlIGN1cmx5IGJyYWNrZXRzLCB5b3UgbmVlZCB0byBzcGVjaWZ5IG5vZGVzICh2YXJpYWJsZXMpIGFuZCBsaW5rcy4gRm9yIG5vZGVzLCB1c2UgYSBzdGF0ZW1lbnQgbGlrZSAnWFsuLi5dJywgYW5kIHdpdGhpbiB0aGUgYnJhY2tldHMsIHlvdSBzcGVjaWZ5IHByb3BlcnRpZXMgc3VjaCBhcyBwb3NpdGlvbnMgKCdwb3MgPSAuLi4nKS4gRm9yIGxpbmtzLCB5b3Ugc3BlY2lmeSB0aGUgbGlua3MgYmV0d2VlbiBub2Rlcywgc3VjaCBhcyAnWCAtPiBZJy4gTm90ZSB0aGF0IHlvdSBtYXkgYWxzbyBzcGVjaWZ5IHRoZSBwYXRocyB0byBtYWtlIHRoaW5ncyBlYXNpZXIuIA0KYGBge3J9DQojIE5vdGUgdGhhdCB5b3UgbWF5IGFsc28gdXNlIGRpZmZlcmVudCBwYXRocyBzdGF0ZW1lbnRzIGZvciB0aGUgc2FtZSBEQUcsIGFzIGxvbmcgYXMgYWxsIGxpbmtzIGFyZSBpbmNsdWRlZC4gDQpnIDwtIGRhZ2l0dHkoJ2RhZyB7DQogICAgWCBbcG9zPSIwLDEiXQ0KICAgIFQgW3Bvcz0iMSwyIl0NCiAgICBaIFtwb3M9IjIsMiJdDQogICAgVyBbcG9zPSIxLDAiXQ0KICAgIFkgW3Bvcz0iMiwxIl0NCiAgICANCiAgICBYIC0+IFQgPC0gWiAtPiBZDQogICAgWCA8LSBXIC0+IFQgLT4gWQ0KICAgIFcgLT4gWg0KICAgIFgtPiBZDQp9JykNCnBsb3QoZykNCmBgYA0KR2l2ZW4gdGhlIERBRywgeW91IG1heSByZXF1ZXN0IGEgYnVuY2ggb2YgdGhpbmdzLCBzdWNoIGFzIHBhcmVudHMsIGNoaWxkcmVuLCBhbmNlc3RvcnMgYW5kIGRlc2NlbmRhbnRzIG9mIG5vZGVzLiANCmBgYHtyfQ0KI0J5IGNvbnZlbnRpb24sIGRlc2NlbmRhbnRzKGcsdikgYW5kIGFuY2VzdG9ycyhnLHYpIGluY2x1ZGUgdiBidXQgY2hpbGRyZW4oZyx2KSBhbmQgcGFyZW50cyhnLHYpIGRvIG5vdC4NCnBhcmVudHMoZywiWiIpICMgcGFyZW50cyBvZiBaDQphbmNlc3RvcnMoZywiWiIpICMgYW5jZXN0b3JzIG9mIFoNCmNoaWxkcmVuKGcsIlciKSAjY2hpbGRyZW4gb2YgVw0KZGVzY2VuZGFudHMoZywiVyIpICNkZXNjZW5kYW50cyBvZiBXDQpgYGANCg0KIyMjIFBhdGggQW5hbHlzaXMNCkZ1cnRoZXJtb3JlLCB5b3UgY2FuIGFuYWx5emUgdGhlIHBhdGhzIGJldHdlZW4gYW55IHBhaXIgb2Ygbm9kZXMgdXNpbmcgKnBhdGhzKCkqLiBUaGUgZnVuY3Rpb24gcmV0dXJucyBhIGxpc3Qgd2l0aCB0aGUgZmlyc3QgZWxlbWVudCBzaG93aW5nIGFsbCBwYXRocyBhbmQgdGhlIHNlY29uZCB3aGV0aGVyIHBhdGhzIGFyZSBvcGVuIChpLmUuLCBkLXNlcGFyYXRlZCkuIA0KYGBge3J9DQojYWxsIHBhdGhzIGJldHdlZW4gWCBhbmQgWSANCnBhdGhzKGcsIlgiLCJZIikgDQpgYGANCllvdSBjYW4gYWxzbyB0ZXN0IGlmIGNvbmRpdGlvbmluZyBvbiBzb21lIHZhcmlhYmxlcyBkLXNlcGFyYXRlcyBhIHBhaXIgb2Ygbm9kZXMgYnkgdXNpbmcgKmRzZXBhcmF0ZWQqLiANCmBgYHtyfQ0Kbm9kZXMgPC0gYygiVyIsIlkiKQ0KaWYoZHNlcGFyYXRlZChnLCJYIiwiWiIsbm9kZXMpKXsNCiAgbWVzc2FnZSgiWCIsIiBhbmQgIiwgIlkiLCIgYXJlIGluZGVwZW5kZW50LiIpDQp9IGVsc2Ugew0KICBtZXNzYWdlKCJYIiwiIGFuZCAiLCAiWSIsICIgYXJlIG5vdCBpbmRlcGVuZGVudC4iKQ0KfQ0KYGBgDQoNCkFzIGEgbWF0dGVyIG9mIGZhY3QsIHlvdSBtYXkgYWxzbyBnZXQgYWxsIGltcGxpZWQgaW5kZXBlbmRlbmNpZXMgaW4gdGhlIGdyYXBoIHdpdGggdGhlIGZ1bmN0aW9uIGJlbG93OiANCmBgYHtyfQ0KaW1wbGllZENvbmRpdGlvbmFsSW5kZXBlbmRlbmNpZXMoZykNCmBgYA0KIyMjIEFkanVzdG1lbnQgU2V0cw0KR2l2ZW4gYSBEQUcsIHRoZSBwYWNrYWdlIGFsc28gZ2l2ZXMgc3VnZ2VzdGlvbnMgb2YgdGhlIHNldCBvZiB2YXJpYWJsZXMgZm9yIGFkanVzdG1lbnRzIGZvciB0aGUgaWRlbnRpZmljYXRpb24gb2YgYSBjYXVzYWwgZWZmZWN0LiBUaGlzIGZ1bmN0aW9uIG1ha2VzIHVzZSBvZiB0aGUgZG8tY2FsY3VsdXMuIA0KYGBge3J9DQojVG8gZ2V0IGFsbCBzZXRzIG9mIHZhcmlhYmxlcyBmb3IgYmFja2Rvb3IgYWRqdXN0bWVudHMNCnByaW50KCJBbGwgYWRqdXN0bWVudCBzZXRzIikNCmFkanVzdG1lbnRTZXRzKGcsIlgiLCJZIix0eXBlID0gImFsbCIpDQoNCiNUaGUgbWluaW1hbCBzZXQgaWYgInR5cGUiIGlzIG5vdCBzcGVjaWZpZWQNCnByaW50KCJUaGUgbWluaW1hbCBhZGp1c3RtZW50IHNldCIpDQphZGp1c3RtZW50U2V0cyhnLCJYIiwiWSIpDQpgYGANCllvdSBtYXkgYWxzbyB0ZXN0IGlmIGluY2x1ZGluZyBhIG5vZGUgaW4gdGhlIGFkanVzdG1lbnQgc2V0IGlzIHZhbGlkLiANCmBgYHtyfQ0KI3NldCB0aGUgY2F1c2UgYW5kIG91dGNvbWUgdmFyaWFibGUNCmV4cG9zdXJlcyhnKSA8LSAiWCINCm91dGNvbWVzKGcpIDwtICJZIg0KDQojY2hlY2tpbmcgaWYgaW5jbHVkaW5nIFQgaXMgT2theQ0KaXNBZGp1c3RtZW50U2V0KGcsIlQiKQ0KYGBgDQoNCg0KDQoNCg0K