Home > Blockchain >  How to generalize a function to take more arguments? R
How to generalize a function to take more arguments? R

Time:09-22

Seems no one is able to tackle this, so I re-ask:

I would like to use an external function from sjstats package within my own function.

The external function takes 4 arguments as like: https://strengejacke.github.io/sjstats/reference/weighted_sd.html

weighted_mannwhitney(data, x, grp, weights, ...)

A simple call to that external function can be done like this.

weighted_mannwhitney(c12hour ~ c161sex   weight, efc)

I have built a simple function below, which currently only works when provided with data as input - adding arguments produces errors.

I would like to be able to pass on some arguments (data, x, grp, weights) to the internally called external functional, so I can change those arguments for different datasets.

The Question

My attempts at generalizing the function are not successful, can anyone show me how I can do this? I show how I would like to call the generalized function below.

library(sjstats) # has weighted Mann-Whitney function which I would like to automate within own function
library(tidyverse) 

data(efc)
efc$weight <- abs(rnorm(nrow(efc), 1, .3))

# Own working function 
own_funk <- function(data, ...) { 
  # Weighted MannWhitney Test p-value
  res <- data %>%
    summarise(
      across(
        c(c12hour,e17age), 
        ~sjstats:::weighted_mannwhitney.formula(.x ~ c161sex   weight, data)$p.value[[1]]
      )
    ) %>% 
    #round(., 3) %>% 
    tibble::rownames_to_column() %>%  
    pivot_longer(-rowname) %>% 
    pivot_wider(names_from=rowname, values_from=value) %>%
    rename("Outcome" = 1, "P-value" = 2) %>%
    as.data.frame()
  
  return(res)
  
}

Call to own working function

own_funk(efc)

How I would like to call the function

# NB: The x can take on many variables  
own_funk(data = efc, x = c(c12hour,e17age), grp = c161sex, weights = weight)

CodePudding user response:

Somewhat similar to @snaut's solution I'd use map to loop over your x columns/formulas. The difference mainly is that we probably don't want to hard code the variables within the function and rather pass these as an argument to the function.

library(sjstats) # has weighted Mann-Whitney function which I would like to automate within own function
library(tidyverse)
library(survey)

# Own working function 
own_funk <- function(data, x, grp, weights) { 
  # Weighted MannWhitney Test p-value
  
  formula <- paste0(x, " ~ ", grp, "   ", weights)
  
  res <- map2(.x = formula,
              .y = x,
              .f = ~ data |> 
                summarize(!!sym(.y) := sjstats:::weighted_mannwhitney.formula(as.formula(.x), data = data)$p.value[[1]]) %>% 
                #round(., 3) %>% 
                tibble::rownames_to_column() %>%  
                pivot_longer(-rowname) %>% 
                pivot_wider(names_from=rowname, values_from=value) %>%
                rename("Outcome" = 1, "P-value" = 2) %>%
                as.data.frame()) |> 
    bind_rows()
  
  return(res)
  
}

own_funk(data = efc, x = c("c12hour", "e17age"), grp = "c161sex", weights = "weight")

Which gives:

  Outcome     P-value
1 c12hour 0.006806572
2  e17age 0.187765467

CodePudding user response:

sjstats:::weighted_mannwhitney.formula is clearly meant for interactive use and not for programming. sjstats:::weighted_mannwhitney.default seems to be more suited for programming, but still does something with unqouting variable names that I did not quite figure out.

What I do most of the time when I have to use functions created to be used in an interactive way for programming is to create a temporary column with a fixed name and then rename the columns I want to iterate over to that column.

This is what I have done in my solution. I also don't use summarise and across but instead use map_dfr to iterate over the column names and output rows of a tibble.

I did not quite understand what you want to archive with the pivot_longer and pivot_wider but I'm sure you can format the output of my solution to your needs.

library(sjstats) # has weighted Mann-Whitney function which I would like to automate within own function
library(tidyverse) 

data(efc)
efc$weight <- abs(rnorm(nrow(efc), 1, .3))

# Own working function 
own_funk <- function(mydata, ...) { 
  # Weighted MannWhitney Test p-value
  
  map_dfr(
    c("c12hour", "e17age"),
    function(column){
      tmp_data <- mydata %>% 
        rename(tmp_col = {column})
      tibble(
        variable = column,
        `P-value`=sjstats:::weighted_mannwhitney.formula(tmp_col ~ c161sex   weight, data=tmp_data)$p.value[[1]]
      )
    }
    )
  
}

own_funk(efc)
  • Related