I have a nested loop that iterates over a function, but I want to avoid running the nested loop. However, I'm stuck on the implementation of an alternative script that will run and save the output.
Below is the loop, and other useful information to run the complete script.
# data
df = data.frame(y1 = sample(x=0L:1L, size=120, replace=TRUE),
y2 = sample(x=0L:1L, size=120, replace=TRUE),
x1 = sample(x=1L:3L, size=120, replace=TRUE),
x2 = sample(x=1L:3L, size=120, replace=TRUE),
x3 = sample(x=1L:3L, size=120, replace=TRUE),
wgt = sample(runif(120, min=.25, max=.70), replace=TRUE))
#the function
chi2_test <- function(...){
termlabels = sapply(substitute(...()), deparse)
form <- reformulate(termlabels=termlabels, response="wgt")
cross_table = xtabs(form, data=df)
chi2_test = chisq.test(cross_table, correct=TRUE)
return(list(crosstabs = cross_table,
chi2_test = chi2_test)
)
}
# dvs and ivs
dvars = names(df)[1:2]
ivars = names(df)[3:5]
combos = tidyr::crossing(dvars, ivars)
# the loop: where I need some help with
for (i in combos$dvars){
for (j in combos$ivars){
cat(i, "by", j)
print(chi2_test(df[, i], df[, j]))
}
}
The nested loop is not needed as the full combination was already created with crossing
. So, just loop over the sequence of rows of combos
, extract the names corresponding to each row, subset the df
column based on that and assign the output to an initialized list
of the same length as number of roww of combos
out <- vector('list', nrow(combos))
names(out) <- do.call(paste, c(combos, sep = " by "))
for(i in seq_along(combos$dvars))
out[[i]] <- chi2_test(df[, combos$dvars[i]], df[, combos$ivars[i]])
-output
> out[1]
$`y1 by x1`
$`y1 by x1`$crosstabs
df[, combos$ivars[i]]
df[, combos$dvars[i]] 1 2 3
0 10.926195 8.558175 6.373337
1 13.388605 8.971302 8.481009
$`y1 by x1`$chi2_test
Pearson's Chi-squared test
data: cross_table
X-squared = 0.12113, df = 2, p-value = 0.9412