Creating formulas out of a list of strings

Viewed 85

I have the following code to parse a string into a list called dag_str2. It's coming out as a nested list and I would want it as just a regular list.

dag_str <- "dag{D<-{G}; A<-{D}; A<-{G}; A<-{Q}}" 
dag_str2 <- gsub("dag|\\{|\\}|[[:space:]]","", dag_str) %>%
  str_split(";")

dag_str2
[[1]]
[1] "D<-G" "A<-D" "A<-G" "A<-Q"

I want the output to be a list of formulas like so Output: List like this

"D~G" "A~D+G+Q"

How can I do this in R?

3 Answers

You can continue to parse out your dag_str2 to create your formula notation.

library(dplyr)
library(tidyr)

df <- tibble(str = unlist(dag_str2)) %>% 
  separate(str, c("lhs", "rhs"), sep = "<-") %>% 
  group_by(lhs) %>% 
  summarize(rhs = paste(rhs, collapse = "+"), .groups = "drop") %>% 
  mutate(f = paste(lhs, rhs, sep = "~"))

From here, you can convert to an actual formula easily if you need to.

lapply(df$f, as.formula)
# [[1]]
# A ~ D + G + Q
# <environment: 0x000001af8db7fa20>
# 
# [[2]]
# D ~ G
# <environment: 0x000001af8db7fa20>

Edit Based on Comments

Here is one way to pull out the terms for which you want to build an intercept for.

There is just one new line, bind_rows(). This adds rows for the terms that are in the RHS, but not in the LHS.

df <- tibble(str = unlist(dag_str2)) %>% 
  separate(str, c("lhs", "rhs"), sep = "<-") %>% 
  bind_rows(tibble(lhs = setdiff(.$rhs, .$lhs),
                   rhs = "1")) %>% 
  group_by(lhs) %>% 
  summarize(rhs = paste(rhs, collapse = "+"), .groups = "drop") %>% 
  mutate(f = paste(lhs, rhs, sep = "~"))

You can try.

dag_str <- "dag{D<-{G}; A<-{D}; A<-{G}; A<-{Q}}" 

x <- do.call(rbind, strsplit(strsplit(gsub("dag|[ {}]", "", dag_str), ";")[[1]], "<-"))
y <- aggregate(x[,2], list(x[,1]), paste, collapse="+")
paste(y[,1], y[,2], sep="~")
#[1] "A~D+G+Q" "D~G"    

I've done this for you :

dag_str2 <- gsub(pattern = "dag|\\{|\\}|[[:space:]]", replacement = "", x = "dag{D<-{G}; A<-{D}; A<-{G}; A<-{Q}}")

my_var <- str_split(string = dag_str2, pattern = ";", simplify = TRUE)

my_temp <- as.data.frame(my_var)
my_temp <- as.data.frame(t(my_temp))

my_var <- str_split(string = my_temp$V1, pattern = "<-", n = 2, simplify = TRUE)
my_temp$V1 <- my_var[, 1]
my_temp$V2 <- my_var[, 2]
my_temp <- my_temp[order(my_temp$V1, my_temp$V2),]
my_end <- my_temp %>% group_by(V1) %>% summarise(Test = paste(V2, collapse = "+"))
my_end$Result <- paste(my_end$V1, my_end$Test, sep = "~")
Related