Page 1 of 1

Availability of alternatives different for each class in a LC model

Posted: 25 Apr 2023, 12:23
by DamienJ
I am trying to evaluate whether some heuristic akin to elimination by aspect is present in my data set.
To do that, I wanted to develop a latent class, where the classes differ in the number of alternatives that are considered.
I have modified the LC model in order to do that.
I first, create a list of list for the describing the availability of the different alternatives for the different classes.

Then I tried to modify the code inside the probability function, so that it takes the availability list specific for each class.

However, doing this I hit an error:

Error in apollo_mnl(mnl_settings, functionality) :
Duplicated componentName found (EClass_1). Names must be different for each component.


I do not see what error I made, and whether what I am doing is sound?
I can also share a small dataset to run the model. But I am not sure that I can attach a file to this message.

Damien


Here is the full code:

Code: Select all

rm(list = ls())
apollo_initialise()

# description of the model 
apollo_control = list(
  modelName = "EBA_subsidy", 
  indivID = "interview__key", 
  outputDirectory = "output"
)

load(file = "forForum.RData")


# Vector of parameters, including any that are kept fixed in estimation
# Hypothesis 3 classes (1 RUM 1 EBA Work 1 EBA fodd)
# Preferences are different for each class...

apollo_beta=c(b_ASC  = -2.3,
              b_work_a   = -0.5,
              b_work_b   = 0 ,
              b_work_c   = +0.5 ,
              b_fodd_a = 0.007,
              b_fodd_b = 0.005,
              b_fodd_c = 0.1,
              b_legu_a = 0.1,
              b_legu_b = 0.1,
              b_legu_c = 0.1,
              b_engr_a = -0.1,
              b_engr_b = -0.1,
              b_engr_c = -0.1,
              b_subs_a = -0.1,
              b_subs_b = -0.1,
              b_subs_c = -0.1,
              delta_b  = 0, 
              delta_c  = 0)

# Vector with names (in quotes) of parameters to be kept fixed at their starting value in apollo_beta, use apollo_beta_fixed = c() if none
apollo_fixed = c( )


# ################################################################# #
#### DEFINE LATENT CLASS COMPONENTS                              ####
# ################################################################# #

apollo_lcPars=function(apollo_beta, apollo_inputs){
  lcpars = list()
  lcpars[["beta_work"]] = list(b_work_a, b_work_b, b_work_c)
  lcpars[["beta_fodd"]] = list(b_fodd_a, b_fodd_b, b_fodd_c)
  lcpars[["beta_legu"]] = list(b_legu_a, b_legu_b, b_legu_c)
  lcpars[["beta_engr"]] = list(b_engr_a, b_engr_b, b_engr_c)
  lcpars[["beta_subs"]] = list(b_subs_a, b_subs_b, b_subs_c)
  
  ### Utilities of class allocation model
  V=list()
  V[["class_a"]] = 0 
  V[["class_b"]] = delta_b 
  V[["class_c"]] = delta_c 

  ### Settings for class allocation models
  classAlloc_settings = list(
    classes      = c(class_a=1, class_b=2, class_c=3), 
    avail         = list(class_a=1, class_b=1, class_c=1),
    utilities    = V,  
    componentName = "AllocClass"
  )
  
  lcpars[["pi_values"]] = apollo_classAlloc(classAlloc_settings)
  
  return(lcpars)
}


# Preparing lists of availability for each class of EBA
availa = list()
availa[["EClass_1"]] = list("1"=1, "2"=1, "SQ"=1)
availa[["EClass_2"]] = list("1"=database$avail1Work, "2"=database$avail2Work, "SQ"=1)  ## EBA Work
availa[["EClass_3"]] = list("1"=database$avail1Fodd, "2"=database$avail2Work, "SQ"=1)

# Checking that all that is needed for the model is here i.e. apollo_control, database, apollo_beta & apollo fixed
apollo_inputs = apollo_validateInputs()

# apollo_probabilities
apollo_probabilities=function(apollo_beta, apollo_inputs, functionality="estimate"){
  
  ### Attach inputs and detach after function exit
  apollo_attach(apollo_beta, apollo_inputs)
  on.exit(apollo_detach(apollo_beta, apollo_inputs))
  
  ### Create list of probabilities P
  P = list()

  ### Loop over classes
  for(s in 1:3){

    mnl_settings = list(
      alternatives  = c("1"=1, "2"=2, "SQ"=3), 
      avail         = availa[[s]],
      choiceVar    = CHOICE,
      componentName = paste0("EClass_",s)
    )
    
    print(mnl_settings$componentName)
    
    ### Compute class-specific utilities
    V=list()
    V[["SQ"]]  = b_ASC + beta_work[[s]]*WORKSQ/100 + beta_fodd[[s]]*FODDSQ/10 + beta_legu[[s]]*LEGUSQ + beta_engr[[s]]*ENGRSQ/10 + beta_subs[[s]]*SUBSSQ/10
    V[["1"]]  =          beta_work[[s]]*WORK1/100 + beta_fodd[[s]]*FODD1/10 + beta_legu[[s]]*LEGU1 + beta_engr[[s]]*ENGR1/10 + beta_subs[[s]]*SUBS1/10
    V[["2"]]  =          beta_work[[s]]*WORK2/100 + beta_fodd[[s]]*FODD2/10 + beta_legu[[s]]*LEGU2 + beta_engr[[s]]*ENGR2/10 + beta_subs[[s]]*SUBS2/10
    
    mnl_settings$utilities     = V

    ### Compute within-class choice probabilities using MNL model
    P[[paste0("EClass_",s)]] = apollo_mnl(mnl_settings, functionality) + 0.001 
    
    ### Take product across observation for same individual
    P[[paste0("EClass_",s)]] = apollo_panelProd(P[[paste0("EClass_",s)]], apollo_inputs ,functionality)
    
    }
  
  ### Compute latent class model probabilities
  lc_settings  = list(inClassProb = P, classProb=pi_values)
  P[["model"]] = apollo_lc(lc_settings, apollo_inputs, functionality)
  
  ### Prepare and return outputs of function
  P = apollo_prepareProb(P, apollo_inputs, functionality)
  return(P)
  
}

model = apollo_estimate(apollo_beta, apollo_fixed, 
                        apollo_probabilities, apollo_inputs)

apollo_modelOutput(model)

Re: Availability of alternatives different for each class in a LC model

Posted: 25 Apr 2023, 14:04
by stephanehess
can you share the data/code with me via e-mail, even just a small subset will do

Re: Availability of alternatives different for each class in a LC model

Posted: 25 Apr 2023, 14:28
by DamienJ
Dear Prof Hess,
Just sent a sample data set on your gmail address and contact@apollochoicemodelling.com I hope this will reach you. Thank you.
Damien

Re: Availability of alternatives different for each class in a LC model

Posted: 26 Apr 2023, 05:54
by stephanehess
Damien

two comments

1. I would strongly recommend moving the definition of availability lists from the global environment into the apollo_probabilities function, otherwise things will go wrong in multi-core estimation, for example.

So just have the following inside apollo_probabilities, before your loop over classes (note that I removed the database$ step)

Code: Select all

  availa = list()
  availa[["EClass_1"]] = list("1"=1, "2"=1, "SQ"=1)
  availa[["EClass_2"]] = list("1"=avail1Work, "2"=avail2Work, "SQ"=1)  ## EBA Work
  availa[["EClass_3"]] = list("1"=avail1Fodd, "2"=avail2Work, "SQ"=1)
2. The +0.001 is likely responsible for some of the error messages you are getting, and is not needed

Stephane

Re: Availability of alternatives different for each class in a LC model

Posted: 26 Apr 2023, 06:28
by DamienJ
It now runs well including using multithreading. Thank you. Damien