NewBee
NewBee

Reputation: 1040

Using reformulate to create a formulae with two tilda

I am trying to use reformulate to feed into an R function to create a formula that looks like this.

~ X, ~Y 

To be fed into this type of function:

as.data.frame(svyby(~X,~Y, design, svymean, na.rm= T))

I know that:

reformulate("X","Y")
returns: Y ~ X

How do I modify reformulate to achieve the above formula? I have tried:

reformulate(c(`~`,"X"),c(`~`,"Y")) # throws an error
form <- noquote(paste0("~",x,",","~",column)) # is not accepted int function 

This is the full function I am feeding it into:

Where form contains the 'formulae' portion and where x is pulled in from a vector_vars of c("Q1","Q2") etc., and column is a character variable 'poverty' being fed in from a larger function.

myfun <- function(x){
  form <- noquote(paste0("~",x,",","~",column))
  cbind(as.data.frame(svyby(form, design, svymean, na.rm = T)),
        freq = c(svytable(form, design)))
  
}

do.call(rbind, lapply(vector_vars, myfun))

Data and function for testing

    data <- read_table2("Q50_1   Q50_2   Q38 Q90 pov gender  wgt id
    yes   3   Yes NA   High    M   1.3 A
    NA   4   No  2   Med F   0.4 B
    no   2   NA 4   Low F   1.2 C
    maybe   3   No  2   High    M   0.5 D
    yes   NA   No  NA   High    M   0.7 E
    no   2   Yes 3   Low F   0.56 F
    maybe   4   Yes 2   Med F   0.9 G
    ")
    
    
    design <- svydesign(id =~id,
                        weights  = ~wgt,
                        nest = FALSE,
                        data = data)
    
    vector_vars <- c("Q50_1", "Q38")
    
    
create_df<- function(design, vector_vars, column){
  
  
  # function to retrieve the weighted,  mean and se 
  myfun <- function(x){
    form <- noquote(paste0("~",x,",","~",column))
    cbind(as.data.frame(svyby(form, design, svymean, na.rm = T)),
          freq = c(svytable(form, design)))
  }
  
  
  
  final <- do.call(rbind, lapply(vector_vars, myfun))
  return(final) 
}


create_df(design, 'gender')

Upvotes: 1

Views: 67

Answers (1)

akrun
akrun

Reputation: 887068

From the svyby, the ~X and ~Y used are for different arguments i.e. first is for formula and second for by

library(survey)
myfun <- function(design, x, colnm) {
     
 # // first formula
 fmla <- reformulate(x)
 # // formula for by
 by <- reformulate(colnm)
  # // return a named list
  list(d1 = as.data.frame(svyby(fmla, by, design, svymean, na.rm = TRUE)),
        freq = c(svytable(fmla, design)))
}

-testing

 lapply(vector_vars, function(x) myfun(design, x, "gender"))
[[1]]
[[1]]$d1
  gender Q50_1maybe   Q50_1no se.Q50_1maybe se.Q50_1no
F      F  0.3383459 0.6616541     0.3026058  0.3026058
M      M  0.2000000 0.8000000     0.2148115  0.2148115

[[1]]$freq
maybe    no   yes 
 1.40  1.76  2.00 


[[2]]
[[2]]$d1
  gender     Q38No    Q38Yes  se.Q38No se.Q38Yes
F      F 0.2150538 0.7849462 0.2253182 0.2253182
M      M 0.4800000 0.5200000 0.3317149 0.3317149

[[2]]$freq
  No  Yes 
1.60 2.76 

Based on the results, showed, the column names are different, so rbind wouldn't work. We may use bind_rows from dplyr or rbindlist from data.table with the updated function

myfun <- function(design, x, colnm) {
     
  fmla <- reformulate(x)
  by <- reformulate(colnm)

 d1 <- as.data.frame(svyby(fmla, by, design, svymean, na.rm = TRUE))
 freq <- c(svytable(fmla, design))
 d1[names(freq)] <- as.list(freq)
return(d1)
}

library(data.table)
rbindlist(lapply(vector_vars, function(x) myfun(design, x, "gender")), fill = TRUE)
   gender Q50_1maybe   Q50_1no se.Q50_1maybe se.Q50_1no maybe   no yes     Q38No    Q38Yes  se.Q38No se.Q38Yes  No  Yes
1:      F  0.3383459 0.6616541     0.3026058  0.3026058   1.4 1.76   2        NA        NA        NA        NA  NA   NA
2:      M  0.2000000 0.8000000     0.2148115  0.2148115   1.4 1.76   2        NA        NA        NA        NA  NA   NA
3:      F         NA        NA            NA         NA    NA   NA  NA 0.2150538 0.7849462 0.2253182 0.2253182 1.6 2.76
4:      M         NA        NA            NA         NA    NA   NA  NA 0.4800000 0.5200000 0.3317149 0.3317149 1.6 2.76

Upvotes: 3

Related Questions