Reputation: 1040
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 <- 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
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