Loop over all the variables automatically in R

Viewed 39

I have a dataset of 3 dependent variables (height,color and habit) and 3 independent (rep,block and flower_name). I have 3 replications and 20 blocks each blocks repeated 6 time.

data_com<-data[1:18,]
flower<-(list(rep = c(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
1, 1, 1, 1, 1), block = c(1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 
3, 3, 3, 3, 3, 3), flowername = c("yellow", "orange", "black", 
"black1", "orange1", "violet", "violet1", "violet3", "purple", 
"purple1", "purple3", "red", "red1", "lila", "sky", "pink", "purple_pink", 
"purple_pink1"), height = c(5, 4, 6, 5, 6, 4, 7, 5, 4, 6, 5, 
6, 7, 5, 6, 5, 4, 5), color = c(5, 5, 7, 6, 6, 4, 7, 4, 5, 6, 
5, 6, 7, 5, 6, 6, 7, 7), habit = c(4, 6, 3, 3, 6, 2, 4, 2, 4, 
6, 2, 6, 7, 7, 7, 6, 6, 6)), row.names = c(NA, -18L), class = c("tbl_df", 
"tbl", "data.frame"))

My model looks like this:

data <- readxl::read_excel("flower.xlsx",sheet = 1) 
str(data) 
names(data) 
data$flowername <- as.factor(data$"flowername") 
data$rep <- as.factor(data$"rep") 
data$block <- as.factor(data$"block") 
data$height <- as.numeric(data$"height") 
model <- lmer(height~ 1 + (1|flowername) + (1|rep) , data = data) summary(model)
------------------------------------------------------------------------

And I would like to have a loop which runs over all the dependent variable once. later I would like to save the random effects for all variables as a list and as xlsx, so that I could use it for further analysis. I would also like to save the anova output for all dependent variables as xlsx as well. I am new to R and looping seems readlly difficult for me to understand. any help would be appreciated.

I am also new in stackoverflow so correct me please if the post is not properly formatted. Thank you

1 Answers

First off, your example data does not work just like that. You have too many (flowername) or too few (rep) levels for the low number of rows. This results in errors when fitting the models. The following example data works, however:

data_com<-data[1:18,]
flower<-structure(list(rep = rep(1:2, 9),
              block = c(1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 
                        3, 3, 3, 3, 3, 3),
              flowername = rep(c("yellow", "orange", "black"), 6),
              height = c(5, 4, 6, 5, 6, 4, 7, 5, 4, 6, 5, 
                         6, 7, 5, 6, 5, 4, 5),
              color = c(5, 5, 7, 6, 6, 4, 7, 4, 5, 6, 
                        5, 6, 7, 5, 6, 6, 7, 7),
              habit = c(4, 6, 3, 3, 6, 2, 4, 2, 4, 
                        6, 2, 6, 7, 7, 7, 6, 6, 6)),
         row.names = c(NA, -18L), class = c("tbl_df", 
                                            "tbl", "data.frame"))

flower$flowername <- as.factor(flower$"flowername")
flower$rep <- as.factor(flower$"rep") 
flower$block <- as.factor(flower$"block") 
flower$height <- as.numeric(flower$"height") 

So, to "automatically" run through your dependent variables, you need to make a function that fits the model and extracts the results that you are interested in:

get.re <- function(dependent, dat) {
  require(lme4)
  dat$dependent <- dat[[dependent]] # specifies the dependent variable
  model <- lmer(dependent ~ 1 + (1|flowername) + (1|rep),
                data = dat) # fits the model
  cat("\n\n============ Model for dependent:", dependent, "============\n")
  print(summary(model)) # shows you the summary
  ranef(model) # returns the random effects of the model
}

# make a vector of the dependent variable names
dependents <- c("height", "color", "habit")

# apply the function to each dependent variable
fits.ls <- lapply(dependents,
                  get.re,
                  dat = flower)
names(fits.ls) <- dependents # name the list elements

The random effects of each model are given as a list of matrices (or data frames, not sure) where the row names are the levels of your random factors. The following code collapses these nested lists of matrices into one data frame per model. Then we save these data frames to an xlsx and use one sheet per model/df.

fits.dfs <- lapply(fits.ls,
                   function(x) {out <- dplyr::bind_rows(lapply(x,
                                                               function(y) data.frame(level = rownames(y),
                                                                                      value = y[,1]) ),
                                                        .id = "")
                                out}
                   )

library(openxlsx)
wb <- buildWorkbook(fits.dfs)
saveWorkbook(wb, "RandomEffects.xlsx")

Edit:

To keep only random effects of flowername and put all of them (from all fitted models) into one excel sheet, transform your output list (fit.ls) as follows. This replaces the last code block:

fits.df <- lapply(fits.ls,
                  function(x) {dplyr::bind_rows(x$flowername)})
fits.df <- dplyr::bind_cols(fits.df)
colnames(fits.df) <- names(fits.ls)
fits.df <- cbind(rownames(fits.df), fits.df) # flowernames as a column so it is visible in the xlsx
openxlsx::write.xlsx(fits.df, "RandomEffects.xlsx")
Related