Skip to content

Instantly share code, notes, and snippets.

View andrewheiss's full-sized avatar
👨‍💻
#rstats-ing all the things

Andrew Heiss andrewheiss

👨‍💻
#rstats-ing all the things
View GitHub Profile
library(tidyverse)
library(kableExtra)
library(gt)
library(palmerpenguins)
penguins <- penguins %>% drop_na(sex)
# With kableExtra
penguins %>%
group_by(species, island, sex) %>%
library(tidyverse)
library(gapminder)
# Using ifelse() with just one condition (good)
gapminder_new <- gapminder %>%
mutate(is_africa = ifelse(continent == "Africa", "Africa", "Not Africa"))
# Using ifelse() with nested conditions (ew)
gapminder_new <- gapminder %>%
mutate(
data_to_plug_in_cat <- expand.grid(
sex = c("female", "male"),
bill_length_mm = c(40, 44, 48),
body_mass_g = mean(penguins$body_mass_g)
)
data_to_plug_in_cat_mat <- model.matrix(
~ 0 + ., data = data_to_plug_in_cat
)

The approach I typically take is to draw them as a pseudo node that points at the middle of a path between two real nodes (see Figure 7 here https://royalsocietypublishing.org/doi/10.1098/rspb.2020.2815 where Q interacts with/modifies X (and how to draw it with R: https://gist.github.com/andrewheiss/6546a22672a13a4eacd8a9a726eac88a). It’s just like Figure 3A in the Attia et al. article too (https://academic.oup.com/ije/article/51/4/1047/6607680), and Laubach, Murray, et al. have a longer appendix about it all too.

It’s a tricky solution because the regular rules of do-calculus don’t apply, since the Q node isn’t really in the DAG in normal ways.

In practice, what I’ve generally seen is that people generally don’t care about interaction nodes because interactions are a statement of functional form and DAGs are supposed to be function-agnostic.

For instance, if you have a situation like y ~ x + a + a*x, where a is binary, and your main treatment is x, the causal effect of x depends on whether or

library(tidyverse)

# geom_bar() doesn't need a variable mapped to the y-axis; it calculates it on its own behind the scenes
ggplot(mpg, aes(x = drv, fill = factor(year))) +
  geom_bar()

library(tidyverse)
library(marginaleffects)
library(broom)
library(palmerpenguins)

penguins <- penguins %>% drop_na(sex)

# Marginal means in conjoint world are just the averages for each of the levels in a factor 
# variable included in a regression model (i.e. instead of using an omitted reference 
library(tidyverse)
library(broom)

# Model with a cateogorical predictor
example_model <- lm(hwy ~ displ + drv, data = mpg)

# Extract all the right-hand variables
rhs <- all.vars(stats::update(formula(example_model), 0 ~ .))
rhs
library(tidyverse)
library(sf)
library(rnaturalearth)
library(countrycode)
library(gapminder)

# rerturnclass = "sf" makes it so the resulting dataframe has the special
# sf-enabled geometry column
world_map <- ne_countries(scale = 50, returnclass = "sf") %>% 
library(tidyverse)
library(palmerpenguins)
library(patchwork)
library(rcartocolor)
library(scales)

# Clean up the data
penguins <- penguins |> 
  drop_na(sex) |>