Home > Software engineering >  Converting a Nested For Loop into `sapply()` in R
Converting a Nested For Loop into `sapply()` in R

Time:01-26

I have been trying to create a series of coplots using a nested for loop but the loop takes too long to run (the original data set is very big). I have looked at similar questions and they suggest using the sapply function but I am still unclear about how to convert between the 2. I understand I need to create a plotting function to use (see below) but what I don't understand is how the i's and j's of the nested for loop into sapply arguements.

I have made some sample data, the nested for loop that I have been using and the plotting function I created that are below. Could someone walk me through how I convert my nested for loop into sapply arguements. I have been doing all of this in R. Many Thanks

y = rnorm(n = 200, mean = 10, sd = 2)
x1 = rnorm(n = 200, mean = 5, sd = 2)
x2 = rnorm(n = 200, mean = 2.5, sd = 2)
x3 = rep(letters[1:4], each = 50)
x4 = rep(LETTERS[1:8], each = 25)
dat = data.frame(y = y, x1 = x1, x2 = x2, x3 = x3, x4 = x4)

for(i in dat[, 2:3]){
  for(j in dat[, 4:5]){
    coplot(y ~ i | j, rows = 1, data = dat)
  }
}

coplop_fun = function(data, x, y, x, na.rm = TRUE){
  coplot(.data[[y]] ~ .data[[x]] | .data[[z]], data = data, rows = 1)
}

CodePudding user response:

We can use a combination of functions expand.grid, formula and apply to accept character column names into coplot.

# combinations of column names for plotting
vars <- expand.grid(y = "y", x = c("x1", "x2"), z = c("x3", "x4"))

# cycle through column name variations, construct formula for each combination
apply(vars, MARGIN = 1,
    FUN = function(x) coplot(
        formula = formula(paste(x[1], "~", x[2], "|", x[3])),
        data = dat, row = 1
    )
)
 

CodePudding user response:

I think you might be able to use mapply here and not sapply. mapply is similar to sapply but allows for you to pass two inputs instead of one.

y = rnorm(n = 200, mean = 10, sd = 2)
x1 = rnorm(n = 200, mean = 5, sd = 2)
x2 = rnorm(n = 200, mean = 2.5, sd = 2)
x3 = rep(letters[1:4], each = 50)
x4 = rep(LETTERS[1:8], each = 25)
dat = data.frame(y = y, x1 = x1, x2 = x2, x3 = x3, x4 = x4)

for(i in dat[, 2:3]){
  for(j in dat[, 4:5]){
    coplot(y ~ i | j, rows = 1, data = dat)
  }
}

mapply(function(x,j){coplot(dat[["y"]]~x|j,rows =1)}, dat[,2:3],dat[,4:5])

CodePudding user response:

Here's a tidyverse version of @nya's solution with expand.grid() and apply(). Each row in ds_plot_parameters represents a single plot. The equation variable is the string eventually passed to coplot().

Each equation is passed to purrr::walk(), which then calls coplot() to produce one graph each. as.equation() converts the string to an equation.

ds_plot_parameters <- 
  tidyr::expand_grid(
    v = c("x1", "x2"),
    w = c("x3", "x4")
  ) |> 
  dplyr::mutate(
    equation = paste0("y ~ ", v, " | ", w),
  )

ds_plot_parameters$equation |> 
  purrr::walk(
    \(e) coplot(as.formula(e), rows = 1, data = dat)
  )

Gravy: If you want to more input to the graph, then expand ds_plot_parameters to include other things like graph & axis titles.

ds_plot_parameters <- 
  tidyr::expand_grid(
    v = c("x1", "x2"),
    w = c("x3", "x4")
  ) |> 
  dplyr::mutate(
    equation  = paste0("y ~ ", v, " | ", w),
    label_y   = "Outcome (mL)",
    label_x   = paste(v, " (log 10)")
  )

ds_plot_parameters |>
  dplyr::select(
    # Make sure this order exactly matches the function signature
    equation,
    label_x,
    label_y,
  ) |>
  purrr::pwalk(
    .f = \(equation, label_x, label_y) {
      coplot(
        formula = as.formula(equation), 
        xlab    = label_x,
        ylab    = label_y,
        rows    = 1, 
        data = dat
      )
    }
  )


ds_plot_parameters
# # A tibble: 4 x 5
#   v     w     equation    label_y      label_x     
#   <chr> <chr> <chr>       <chr>        <chr>       
# 1 x1    x3    y ~ x1 | x3 Outcome (mL) x1  (log 10)
# 2 x1    x4    y ~ x1 | x4 Outcome (mL) x1  (log 10)
# 3 x2    x3    y ~ x2 | x3 Outcome (mL) x2  (log 10)
# 4 x2    x4    y ~ x2 | x4 Outcome (mL) x2  (log 10)
  •  Tags:  
  • Related