rpurrrpairwise.wilcox.test

How to use purrr::map to get reports of a Wilcox test


I was trying to use report of the R package report to get a report of the results of 2 Wilcoxon tests, one for each Session.

I can obtain the test results but not the text report.

I couldn't find any examples of using purr and report.

library(tidyverse)
library(report)

df <- tibble(Session = c(rep("1", 10), rep("2", 10)),
             scores = sample(20:70, 20),
             group = c(rep("before", 5), rep("after",5),
                       rep("before", 5), rep("after",5)))

# function to compute Wilcoxon test
w_test <- function(df) {
  wilcox.test(scores ~ group, df, paired = TRUE)
}

# testing w_test function for Session 1
dfS1 <- df %>% filter(Session == "1")
w_test(dfS1)
#> 
#>  Wilcoxon signed rank exact test
#> 
#> data:  scores by group
#> V = 4, p-value = 0.4375
#> alternative hypothesis: true location shift is not equal to 0

# this does not work because I can't map wtest to report::report
w <- df %>%
  group_by(Session) %>%
  nest() %>%
  mutate(wtest = map(data, w_test),
         result = map(wtest, report))
#> Could not compute effectsize NA.
#>   Possible reason: Unable to retrieve data from htest object.
#>   Try using
#>   'rb()' directly.
#> Error in `mutate()`:
#> ℹ In argument: `result = map(wtest, report)`.
#> ℹ In group 1: `Session = "1"`.
#> Caused by error in `map()`:
#> ℹ In index: 1.
#> Caused by error in `abs()`:
#> ! non-numeric argument to mathematical function
#> Backtrace:
#>      ▆
#>   1. ├─df %>% group_by(Session) %>% nest() %>% ...
#>   2. ├─dplyr::mutate(...)
#>   3. ├─dplyr:::mutate.data.frame(...)
#>   4. │ └─dplyr:::mutate_cols(.data, dplyr_quosures(...), by)
#>   5. │   ├─base::withCallingHandlers(...)
#>   6. │   └─dplyr:::mutate_col(dots[[i]], data, mask, new_columns)
#>   7. │     └─mask$eval_all_mutate(quo)
#>   8. │       └─dplyr (local) eval()
#>   9. ├─purrr::map(wtest, report)
#>  10. │ └─purrr:::map_("list", .x, .f, ..., .progress = .progress)
#>  11. │   ├─purrr:::with_indexed_errors(...)
#>  12. │   │ └─base::withCallingHandlers(...)
#>  13. │   ├─purrr:::call_with_cleanup(...)
#>  14. │   ├─report (local) .f(.x[[i]], ...)
#>  15. │   └─report:::report.htest(.x[[i]], ...)
#>  16. │     ├─report::report_table(x, model_info = model_info, ...)
#>  17. │     └─report:::report_table.htest(x, model_info = model_info, ...)
#>  18. │       ├─base::do.call(report_effectsize, args)
#>  19. │       ├─report (local) `<fn>`(`<htest>`, model_info = `<named list>`)
#>  20. │       └─report:::report_effectsize.htest(`<htest>`, model_info = `<named list>`)
#>  21. │         └─report:::.report_effectsize_wilcox(x, table, dot_args)
#>  22. │           ├─base::do.call(effectsize::interpret_r, args)
#>  23. │           └─effectsize (local) `<fn>`(NULL)
#>  24. │             └─effectsize::interpret(abs(r), rules)
#>  25. └─base::.handleSimpleError(...)
#>  26.   └─purrr (local) h(simpleError(msg, call))
#>  27.     └─cli::cli_abort(...)
#>  28.       └─rlang::abort(...)

w$report
#> Error in eval(expr, envir, enclos): object 'w' not found
Created on 2023-10-01 with reprex v2.0.2

Solution

  • To make report() work with htest object, you probably need to drop data argument from wilcox.test() and change the formula accordingly (relevant github issue):

    library(tidyverse)
    library(report)
    
    df <- tibble(Session = c(rep("1", 10), rep("2", 10)),
                 scores = sample(20:70, 20),
                 group = c(rep("before", 5), rep("after",5),
                           rep("before", 5), rep("after",5)))
    
    # using `data`, report() fails:
    wilcox.test(scores ~ group, df, paired = TRUE) |> report()
    #> Could not compute effectsize NA.
    #>   Possible reason: Unable to retrieve data from htest object.
    #>   Try using
    #>   'rb()' directly.
    #> Error in abs(r): non-numeric argument to mathematical function
    
    # without `data`, referring to frame in formula:
    wilcox.test(df$scores ~ df$group, paired = TRUE) |> report()
    #> Effect sizes were labelled following Funder's (2019) recommendations.
    #> 
    #> The Wilcoxon signed rank exact test testing the difference in ranks between
    #> df$scores and df$group suggests that the effect is negative, statistically
    #> significant, and very large (W = 8.00, p = 0.049; r (rank biserial) = -0.71,
    #> 95% CI [-0.92, -0.18])
    

    With changed function:

    w_test <- function(df) {
      wilcox.test(df$scores ~ df$group, paired = TRUE)
    }
    
    df %>%
      group_by(Session) %>%
      nest() %>%
      mutate(wtest = map(data, w_test),
             result = map(wtest, report))
    #> Warning: There was 1 warning in `mutate()`.
    #> ℹ In argument: `wtest = map(data, w_test)`.
    #> ℹ In group 2: `Session = "2"`.
    #> Caused by warning in `wilcox.test.default()`:
    #> ! cannot compute exact p-value with ties
    #> # A tibble: 2 × 4
    #> # Groups:   Session [2]
    #>   Session data              wtest   result      
    #>   <chr>   <list>            <list>  <list>      
    #> 1 1       <tibble [10 × 2]> <htest> <report [1]>
    #> 2 2       <tibble [10 × 2]> <htest> <report [1]>
    

    Depending on what you need to be reported, you can also extract values directly from htest object or pass it through broom::tidy() instead of report().

    Another alternative would be {rstatix}, it's designed to be "pipe-friendly" and works with grouped frames:

    library(rstatix, warn.conflicts = FALSE)
    df %>%
      group_by(Session) %>% 
      wilcox_test(scores ~ group, paired = TRUE, detailed = TRUE)
    #> # A tibble: 2 × 13
    #>   Session estimate .y.    group1 group2    n1    n2 statistic     p conf.low
    #> * <chr>      <dbl> <chr>  <chr>  <chr>  <int> <int>     <dbl> <dbl>    <dbl>
    #> 1 1           13   scores after  before     5     5        13 0.188   -13   
    #> 2 2           25.0 scores after  before     5     5        14 0.104     4.50
    #> # ℹ 3 more variables: conf.high <dbl>, method <chr>, alternative <chr>
    

    Created on 2023-10-01 with reprex v2.0.2