runehaubo / ordinal

R package ordinal: Regression Models for Ordinal Data
Other
31 stars 12 forks source link

Using nominal_test() in a user made function #24

Open cindyyawencheng opened 4 years ago

cindyyawencheng commented 4 years ago

I would like to create a simple function that i) automates the process of evaluating whether particular independent variables violate the parallel regression assumption and then ii) subsequently returns a regression with the in which the independent variables that do violate the parallel regression assumption are evaluated accordingly. To that end, I've written the following code, where I use the nominal_test() function in the ordinal package to implement part i).

runOrdReg = function(dv,  vnames, dataset){
       require(ordinal)
       # run parallel regression
       parallelReg = clm(formula(paste0(dv, '~', paste(vnames, collapse = '+'))), 
                       data = dataset, link = 'logit')

       # implement nominal_test
       nominalTest = nominal_test(parallelReg)

      # select outcome and nominal variables based off of nominal test
        nomVars = rownames(nominalTest)[which(nominalTest$`Pr(>Chi)`<0.1)]      
        outcomeVars = setdiff(vnames, nomVars)

      # run non parallel regression
          nonParallelReg  <- clm(as.formula(paste0(dv, '~', paste(outcomeVars, collapse = '+'))),
                 nominal = as.formula(paste0( '~', paste(nomVars, collapse = '+'))) ,
                 data = dataset, link = 'logit')

       return(nonParallelReg)
}

However, I have found that for some reason, the nominal_test() function does not work as desired when using it inside another function. To illustrate, if you run the following code,

set.seed(2)
data = data.frame(y = factor(sample(1:4, 100, replace = TRUE)),
                  x1 = rnorm(100),
                  x2 = rnorm(100, 10, 5),
                  x3 = sample(-100:100, 100, replace = TRUE))

runOrdReg = function(dv,  vnames, dataset){
       require(ordinal)
       # run parallel regression
       parallelReg = clm(formula(paste0(dv, '~', paste(vnames, collapse = '+'))), 
                       data = dataset, link = 'logit')
}
model_func = runOrdReg(dv = 'y', vnames = paste0('x', 1:3), dataset = data)
nominal_test(model_func)

The nominal_test() function does not return any results. However, running the same model, but outside of the user-created function, nominal_test() DOES return results, as evidenced if you run the following:

model = clm(as.formula(paste0('y', '~', paste(paste0('x', 1:3), collapse = '+'))), data = data, link = 'logit')
nominal_test(model)

I'm guessing the issue lies somewhere in the source code for nominal_test(), would it be possible to look into this? Thanks very much!

runehaubo commented 3 years ago

Thanks for the report - it's now on the to-do list.

FunkMonkey commented 11 months ago

I have similar problems with dynamically created formulas, which seem to internally throw an exception, which is not forwarded outside of nominal_test. It probably has something to do with the environments, but it seems that using do.call when calling clm fixes the problem, e.g.

model = do.call(clm, list(as.formula(paste0('y', '~', paste(paste0('x', 1:3), collapse = '+'))), data = data, link = 'logit'))