-
Notifications
You must be signed in to change notification settings - Fork 12
/
README.Rmd
399 lines (316 loc) · 13.5 KB
/
README.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
---
output: github_document
editor_options:
markdown:
wrap: 72
---
<!-- README.md is generated from README.Rmd. Please edit that file -->
```{r, echo=FALSE}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>",
fig.path = "man/figures/",
dpi = 600,
fig.asp = 0.618,
fig.width = 6
)
```
<!-- badges: start -->
[![R-CMD-check](https://github.com/flyaflya/causact/workflows/R-CMD-check/badge.svg)](https://github.com/flyaflya/causact/actions)
[![CRAN
status](https://www.r-pkg.org/badges/version/causact)](https://cran.r-project.org/package=causact)
[![Codecov test
coverage](https://codecov.io/gh/flyaflya/causact/branch/master/graph/badge.svg)](https://app.codecov.io/gh/flyaflya/causact?branch=master)
[![Lifecycle:Maturing](https://img.shields.io/badge/Lifecycle-Maturing-007EC6)](https://img.shields.io/badge/Lifecycle-Maturing-007EC6)
[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.6949489.svg)](https://doi.org/10.5281/zenodo.6949489)
[![DOI](https://joss.theoj.org/papers/10.21105/joss.04415/status.svg)](https://doi.org/10.21105/joss.04415)
<!-- badges: end -->
# causact
*Accelerate computational Bayesian inference workflows* in R through
interactive modelling, visualization, and inference. The package
leverages directed acyclic graphs (DAGs) to create a unified language
language for business stakeholders, statisticians, and programmers. Due
to its visual nature and simple model construction, `causact` serves as
a great entry-point for newcomers to computational Bayesian inference.
> The `causact` package offers robust support for both foundational and
> advanced Bayesian models. While introductory models are well-covered,
> the utilization of multi-variate distributions such as multi-variate
> normal, multi-nomial, or dirichlet distributions, may not work as
> expected. There are ongoing enhancements in the pipeline to facilitate
> construction of these more intricate models.
```{r demoGif, out.width = "40%", echo = FALSE, fig.align = "center"}
knitr::include_graphics("man/figures/introScreenshot.png")
```
While proficiency in R is the only requirement for users of this
package, it also functions as a introductory probabilistic programming
language, seamlessly incorporating the `numpyro` Python package to
facilitate Bayesian inference without the need to learn any syntax
outside of the package or R. Furthermore, the package streamlines the
process of indexing categorical variables, which often presents a
complex syntax hurdle for those new to computational Bayesian methods.
For enhanced learning, the `causact` package for Bayesian inference is
featured in `A Business Analyst's Introduction to Business Analytics`
available at <https://www.causact.com/>.
> Feedback and encouragement is appreciated via github issues.
## Installation Guide
To install the `causact` package, follow the steps outlined below:
### CRAN Release Version (Recommended)
For the current stable release, which is tailored to integrate with
Python's `numpyro` package, employ the following command:
``` r
install.packages("causact")
```
Then, see [Essential Dependencies] if you want to be able to automate
sampling using the `numpyro` package.
### Development Release
If you want the most recent development version (not recommended),
execute the following:
``` r
install.packages("remotes")
remotes::install_github("flyaflya/causact")
```
### Essential Dependencies
To harness the full potential of `causact` for DAG visualization and
Bayesian posterior analysis, it's vital to ensure proper integration
with the `numpyro` package. Given the Python-based nature of `numpyro`,
a few essential dependencies must be in place. Execute the following
commands after installing `causact`:
``` r
library(causact)
install_causact_deps()
```
If prompted, respond with `Y` to any inquiries related to installing miniconda.
> **Note**: If opting for installation on Posit Cloud, temporarily
> adjust your project's RAM to 4GB during the installation process
> (remember to APPLY CHANGES). This preemptive measure helps avoid
> encountering an
> `Error: Error creating conda environment [exit code 137]`. After
> installation, feel free to revert the settings to 1GB of RAM.
> **Note**: The September 11, 2023 release of `reticulate` (`v1.32`) has
> caused an issue which gives a
> `TypeError: the first argument must be callable` error when using
> `dag_numpyro()` on windows. If you experience this, install the dev
> version of `reticulate` by following the below steps:
>
> 1) Install RTOOLS by using installer at:
> <https://cran.r-project.org/bin/windows/Rtools/>
>
> 2) Run this to get the dev version of `reticulate`:
```
# install DEV version of reticulate
# install.packages("pak") #uncomment as needed
pak::pak("rstudio/reticulate")
```
### Retrograde Compatibility (Not Advised)
In cases where legacy compatibility is paramount and you still rely on
the operationality of the `dag_greta()` function, consider installing
`v0.4.2` of the `causact` package. However, it's essential to emphasize
that this approach is **not recommended** for general usage:
``` r
### EXERCISE CAUTION BEFORE EXECUTING THESE LINES
### Only proceed if dag_greta() is integral to your existing codebase
install.packages("remotes")
remotes::install_github("flyaflya/[email protected]")
```
Your judicious choice of installation method will ensure a seamless and
effective integration of the `causact` package into your computational
toolkit.
## Usage
Example taken from
<https://www.causact.com/graphical-models-tell-joint-distribution-stories.html#graphical-models-tell-joint-distribution-stories>
with the packages `dag_foo()` functions further described here:
<https://www.causact.com/causact-quick-inference-with-generative-dags.html#causact-quick-inference-with-generative-dags>
### Create beautiful model visualizations.
```{r defineGraph, results = "hide", echo = FALSE}
library(causact)
graph = dag_create() %>%
dag_node(descr = "Get Card",label = "y",
rhs = bernoulli(theta),
data = carModelDF$getCard) %>%
dag_node(descr = "Card Probability",label = "theta",
rhs = beta(2,2),
child = "y") %>%
dag_plate(descr = "Car Model", label = "x",
data = carModelDF$carModel,
nodeLabels = "theta",
addDataNode = TRUE)
```
```{r cardP, eval = FALSE}
library(causact)
graph = dag_create() %>%
dag_node(descr = "Get Card", label = "y",
rhs = bernoulli(theta),
data = carModelDF$getCard) %>%
dag_node(descr = "Card Probability", label = "theta",
rhs = beta(2,2),
child = "y") %>%
dag_plate(descr = "Car Model", label = "x",
data = carModelDF$carModel,
nodeLabels = "theta",
addDataNode = TRUE)
graph %>% dag_render()
```
```{r cardPlatePlot, out.width = "60%", echo = FALSE}
knitr::include_graphics("man/figures/cardPlot.png")
```
### Hide model complexity, as appropriate, from domain experts and other less statistically minded stakeholders.
```{r cardPSL, eval = FALSE}
graph %>% dag_render(shortLabel = TRUE)
```
```{r cardPlateSLPlot, out.width = "50%", echo = FALSE}
knitr::include_graphics("man/figures/cardPlotShortLabel.png")
```
### Get posterior while automatically running the underlying `numpyro` code
```{r greta, warning = FALSE, message = FALSE}
drawsDF = graph %>% dag_numpyro()
drawsDF ### see top of data frame
```
> **Note**: if you have used older versions of causact, please know that
> dag_numpyro() is a drop-in replacement for dag_greta().
### Get quick view of posterior distribution
```{r gretaPost, fig.cap = "Credible interval plots.", fig.width = 6.5, fig.height = 4, out.width = "70%"}
drawsDF %>% dagp_plot()
```
### OPTIONAL: See `numpyro` code without executing it (for debugging or learning)
```{r gretaCode, warning = FALSE, message = TRUE}
numpyroCode = graph %>% dag_numpyro(mcmc = FALSE)
```
## Getting Help and Suggesting Improvements
Whether you encounter a clear bug, have a suggestion for improvement, or
just have a question, we are thrilled to help you out. In all cases,
please file a [GitHub
issue](https://github.com/flyaflya/causact/issues). If reporting a bug,
please include a minimal reproducible example.
## Contributing
We welcome help turning `causact` into the most intuitive and fastest
method of converting stakeholder narratives about data-generating
processes into actionable insight from posterior distributions. If you
want to help us achieve this vision, we welcome your contributions after
reading the [new contributor
guide](https://github.com/flyaflya/causact/blob/master/.github/contributing.md).
Please note that this project is released with a [Contributor Code of
Conduct](https://github.com/flyaflya/causact/blob/master/CODE_OF_CONDUCT.md).
By participating in this project you agree to abide by its terms.
## Further Usage
For more info, see
`A Business Analyst's Introduction to Business Analytics` available at
<https://www.causact.com>. You can also check out the package's
vignette: `vignette("narrative-to-insight-with-causact")`. Two
additional examples are shown below.
## Prosocial Chimpanzees Example from Statistical Rethinking
> McElreath, Richard. Statistical rethinking: A Bayesian course with
> examples in R and Stan. Chapman and Hall/CRC, 2018.
```{r chimpsGraph, results ="hide", warning = FALSE, message = FALSE}
library(tidyverse)
library(causact)
# data object used below, chimpanzeesDF, is built-in to causact package
graph = dag_create() %>%
dag_node("Pull Left Handle","L",
rhs = bernoulli(p),
data = causact::chimpanzeesDF$pulled_left) %>%
dag_node("Probability of Pull", "p",
rhs = 1 / (1 + exp(-((alpha + gamma + beta)))),
child = "L") %>%
dag_node("Actor Intercept","alpha",
rhs = normal(alphaBar, sigma_alpha),
child = "p") %>%
dag_node("Block Intercept","gamma",
rhs = normal(0,sigma_gamma),
child = "p") %>%
dag_node("Treatment Intercept","beta",
rhs = normal(0,0.5),
child = "p") %>%
dag_node("Actor Population Intercept","alphaBar",
rhs = normal(0,1.5),
child = "alpha") %>%
dag_node("Actor Variation","sigma_alpha",
rhs = exponential(1),
child = "alpha") %>%
dag_node("Block Variation","sigma_gamma",
rhs = exponential(1),
child = "gamma") %>%
dag_plate("Observation","i",
nodeLabels = c("L","p")) %>%
dag_plate("Actor","act",
nodeLabels = c("alpha"),
data = chimpanzeesDF$actor,
addDataNode = TRUE) %>%
dag_plate("Block","blk",
nodeLabels = c("gamma"),
data = chimpanzeesDF$block,
addDataNode = TRUE) %>%
dag_plate("Treatment","trtmt",
nodeLabels = c("beta"),
data = chimpanzeesDF$treatment,
addDataNode = TRUE)
```
### See graph
```{r chimpsGraphRenderCode, eval = FALSE, warning = FALSE, message = FALSE}
graph %>% dag_render(width = 2000, height = 800)
```
```{r chimpsGraphRenderPlot, out.width = "120%", echo = FALSE}
knitr::include_graphics("man/figures/chimpStat.png")
```
### Communicate with stakeholders for whom the statistics might be distracting
```{r chimpsGraphRenderSL, eval=FALSE, message=FALSE, warning=FALSE}
graph %>% dag_render(shortLabel = TRUE)
```
```{r chimpsGraphRenderPlotSL, out.width = "100%", echo = FALSE}
knitr::include_graphics("man/figures/chimpStatSL.png")
```
### Compute posterior
```{r chimpsGraphGreta, warning = FALSE, message = FALSE}
drawsDF = graph %>% dag_numpyro()
```
### Visualize posterior
```{r chimpsGraphPost, out.width = "100%", fig.width = 9, fig.height = 6, warning = FALSE, message = FALSE}
drawsDF %>% dagp_plot()
```
## Eight Schools Example from Bayesian Data Analysis
> Gelman, Andrew, Hal S. Stern, John B. Carlin, David B. Dunson, Aki
> Vehtari, and Donald B. Rubin. Bayesian data analysis. Chapman and
> Hall/CRC, 2013.
```{r eightschoolsGraph, results ="hide", warning = FALSE, message = FALSE}
library(tidyverse)
library(causact)
# data object used below, schoolDF, is built-in to causact package
graph = dag_create() %>%
dag_node("Treatment Effect","y",
rhs = normal(theta, sigma),
data = causact::schoolsDF$y) %>%
dag_node("Std Error of Effect Estimates","sigma",
data = causact::schoolsDF$sigma,
child = "y") %>%
dag_node("Exp. Treatment Effect","theta",
child = "y",
rhs = avgEffect + schoolEffect) %>%
dag_node("Pop Treatment Effect","avgEffect",
child = "theta",
rhs = normal(0,30)) %>%
dag_node("School Level Effects","schoolEffect",
rhs = normal(0,30),
child = "theta") %>%
dag_plate("Observation","i",nodeLabels = c("sigma","y","theta")) %>%
dag_plate("School Name","school",
nodeLabels = "schoolEffect",
data = causact::schoolsDF$schoolName,
addDataNode = TRUE)
```
### See graph
```{r eightschoolsGraphRenderCode, eval = FALSE, warning = FALSE, message = FALSE}
graph %>% dag_render()
```
```{r eightschoolsGraphRenderPlot, out.width = "100%", echo = FALSE}
knitr::include_graphics("man/figures/eightSchoolStat.png")
```
### Compute posterior
```{r eightschoolsGraphGreta, warning = FALSE, message = FALSE}
drawsDF = graph %>% dag_numpyro()
```
### Visualize posterior
```{r eightschoolsGraphPost, out.width = "100%", eval = FALSE, fig.width = 9, fig.height = 6, warning = FALSE, message = FALSE}
drawsDF %>% dagp_plot()
```
```{r eightschoolsGraphRenderPost, out.width = "100%", echo = FALSE}
knitr::include_graphics("man/figures/eightschoolsGraphPost-1.png")
```