writer_typer
writer_typer

Reputation: 798

How to apply a function with multiple arguments and create a dataframe?

I have a function that takes in two arguments fre(data, var). I would like to apply this function to a few selected variables and create a dataframe by binding them by rows. I've done it the long way through this code.

Function:

fre <- function(.data, var) {
  var <- rlang::ensym(var)
  abc <- questionr::na.rm(.data[, rlang::as_string(var)])
  abc <- questionr::freq(abc)
  abc <- cbind(Label = rownames(abc), abc)
  abc <- questionr::rename.variable(abc, "n", "Frequency")
  abc <- questionr::rename.variable(abc, "%", "Percent")
  abc <- tidyr::separate(abc, Label, into = c("Value", "Label"), sep = "] ")
  row.names(abc) <- NULL
  abc <- abc %>% dplyr::mutate(Value = gsub("\\[|\\]", "", Value)) %>% 
    dplyr::select(Label, Value, Frequency, Percent) %>% 
    select(Label, Percent) 
  abc$Percent <- paste0(round(abc$Percent), "%")
  abc <- abc %>% 
    tidyr::pivot_wider(names_from = Label, values_from = Percent) 
  Label <- var_label(.data[[var]])
  Name <- deparse(substitute(var))
  abc <- cbind(Name, Label, abc)
  abc
}

Read example data:

dat <- haven::read_spss("http://staff.bath.ac.uk/pssiw/stats2/SAQ.sav")

Run function with select variable names:

r3 <- fre(dat, Q03)
r6 <- fre(dat, Q06)
r7 <- fre(dat, Q07)
r8 <- fre(dat, Q08)
r10 <- fre(dat, Q10)

Create dataset by binding rows:

rbind(r3, r6, r7, r8, r10)

Result:

enter image description here

I'm looking for a way to simplify this code. I've tried using lapply but I'm getting different errors. For instance, when I try running lapply(list_var, fre), I get this error: Error in is_string(x) : argument "var" is missing, with no default. I know I need to pass multiple arguments to lapply, but I'm not sure how to do that with the function I created. Also, I'm looking for other ways apart from using lapply to quickly create a dataframe.

Upvotes: 0

Views: 151

Answers (1)

Ronak Shah
Ronak Shah

Reputation: 388817

Change your function to accept string arguments :

fre <- function(.data, var) {
  abc <- questionr::na.rm(.data[, var])
  abc <- questionr::freq(abc)
  abc <- cbind(Label = rownames(abc), abc)
  abc <- questionr::rename.variable(abc, "n", "Frequency")
  abc <- questionr::rename.variable(abc, "%", "Percent")
  abc <- tidyr::separate(abc, Label, into = c("Value", "Label"), sep = "] ")
  row.names(abc) <- NULL
  abc <- abc %>% dplyr::mutate(Value = gsub("\\[|\\]", "", Value)) %>% 
    dplyr::select(Label, Value, Frequency, Percent) %>% 
    select(Label, Percent) 
  abc$Percent <- paste0(round(abc$Percent), "%")
  abc <- abc %>% 
    tidyr::pivot_wider(names_from = Label, values_from = Percent) 
  Label <- var_label(.data[[var]])
  Name <- var
  abc <- cbind(Name, Label, abc)
  abc
}

Then pass column names to fre function as string using lapply.

cols <- c('Q03', 'Q06', 'Q07', 'Q08', 'Q10')
result <- do.call(rbind, lapply(cols, fre, .data = dat))
#Or a bit shorter
#result <- purrr::map_df(cols, fre, .data = dat))
result

#  Name                                       Label Strongly agree Agree Neither Disagree
#1  Q03               Standard deviations excite me            19%   26%     34%      17%
#2  Q06       I have little experience of computers            27%   44%     13%      10%
#3  Q07                       All computers hate me             7%   34%     26%      24%
#4  Q08       I have never been good at mathematics            15%   58%     19%       6%
#5  Q10 Computers are useful only for playing games            14%   57%     18%      10%
#  Strongly disagree
#1                3%
#2                6%
#3                8%
#4                3%
#5                2%

Upvotes: 1

Related Questions