Search code examples
revaluationscoping

solving scoping issure in a custom function to extract data from `htest` object


I am struggling with some scoping issues where I am trying to extract dataframe.

Here is a portion of a larger custom function to extract data from McNemar's test and other htest objects:

get_data <- function(x, ...) {
  data_name <- unlist(strsplit(x$data.name, " (and|by) "))
  data_call <- lapply(data_name, str2lang)
  columns <- lapply(data_call, eval)
  as.table(columns[[1]])
}

using outside function environment

The function works as expected:

# data
Performance <-
  matrix(c(794, 86, 150, 570),
    nrow = 2,
    dimnames = list(
      "1st Survey" = c("Approve", "Disapprove"),
      "2nd Survey" = c("Approve", "Disapprove")
    )
  )

# using the function
mod <- stats::mcnemar.test(Performance)
get_data(mod) # it works!

#>             2nd Survey
#> 1st Survey   Approve Disapprove
#>   Approve        794        150
#>   Disapprove      86        570

using inside function environment

Doesn't work unfortunately

foo <- function(data) {
  mod <- stats::mcnemar.test(data)
  print(mod) # making sure data is being read internally
  
  get_data(mod) # it doesn't work :(
}

foo(Performance)
#> 
#>  McNemar's Chi-squared test with continuity correction
#> 
#> data:  data
#> McNemar's chi-squared = 16.818, df = 1, p-value = 4.115e-05
#> Error in as.table.default(columns[[1]]): cannot coerce to a table

Is there any way to make this work, either by changing the custom function to extract data (get_data) or by modifying the function where it is called (foo)?


Solution

  • As @RuiBarradas mentioned in the comments, the mcnemar.test is creating the list element 'data.name' as the input data instead of the value stored in it. It can be changed after applying the test

    get_data <- function(x, ...) {
       data_name <- unlist(strsplit(x$data.name, " (and|by) "))
       data_call <- lapply(data_name, str2lang)
       columns <- lapply(data_call, eval)
       as.table(columns[[1]])
       
       
     }
     
     
    foo <- function(data) {
       
       mod <- stats::mcnemar.test(data)
       mod$data.name <- deparse(substitute(data))
       print(mod) # making sure data is being read internally
      
       get_data(mod) # it doesn't work :(
     }
    
    foo(Performance)
    #   McNemar's Chi-squared test with continuity correction
    
    #data:  Performance
    #McNemar's chi-squared = 16.818, df = 1, p-value = 4.115e-05
    
    #            2nd Survey
    #1st Survey   Approve Disapprove
    #  Approve        794        150
    #  Disapprove      86        570
    

    Or use get

    get_data <- function(x, ...) { 
        data_name <- unlist(strsplit(x$data.name, " (and|by) "))
        as.table(get(data_name, envir = parent.frame()))
        }
    foo(Performance)
    #McNemar's Chi-squared test with continuity correction
    
    #data:  Performance
    #McNemar's chi-squared = 16.818, df = 1, p-value = 4.115e-05
    
    #            2nd Survey
    #1st Survey   Approve Disapprove
    #  Approve        794        150
    #  Disapprove      86        570