Page 1 of 1

LCCM model with two choice models

Posted: 18 Mar 2022, 17:12
by jaimlk77
Hi

I am trying to estimate a LCCM with two choice models in each latent class. Is that possible to estimate in Apollo?

As shown in the attached subset of the R code. I am trying to wrap two MNLs in latent classes. However, I keep getting the following error:

Error in apollo_lc(lc_settings, apollo_inputs, functionality) :
Arguments 'inClassProb' and 'classProb' for model component "LC" must have the same length.


I thought using the apollo_combineModels would resolve this issue but that did not help. Does anyone have any suggestions on how I can resolve this issue?

Thanks,
Jai




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

### Compute class-specific utilities
V_1[["alt_1"]] = asc_1_1[[s]] + b_age_num_1_1[[s]] * (age_num == 1) + b_age_num_2_1[[s]] * (age_num == 2) + b_gender_1[[s]] * (gender_num == 1)
V_1[["alt_2"]] = asc_2_1[[s]] + b_age_num_1_1[[s]] * (age_num == 1) + b_age_num_2_1[[s]] * (age_num == 2) + b_gender_1[[s]] * (gender_num == 1)
V_1[["alt_3"]] = asc_3_1[[s]] + b_age_num_1_1[[s]] * (age_num == 1) + b_age_num_2_1[[s]] * (age_num == 2) + b_gender_1[[s]] * (gender_num == 1)
V_1[["alt_4"]] = asc_4_1[[s]]

mnl_settings_1$utilities = V_1
mnl_settings_1$componentName = paste0("model1_Class_",s)

### Compute within-class choice probabilities using MNL model
P[[paste0("model1_Class_",s)]] = apollo_mnl(mnl_settings_1, functionality)

V_2 = list()

V_2[["alt_1"]] = asc_1_2[[s]] + b_age_num_1_2[[s]] * (age_num == 1) + b_age_num_2_2[[s]] * (age_num == 2) + b_gender_2[[s]] * (gender_num == 1)
V_2[["alt_2"]] = asc_2_2[[s]] + b_age_num_1_2[[s]] * (age_num == 1) + b_age_num_2_2[[s]] * (age_num == 2) + b_gender_2[[s]] * (gender_num == 1)
V_2[["alt_3"]] = asc_3_2[[s]] + b_age_num_1_2[[s]] * (age_num == 1) + b_age_num_2_2[[s]] * (age_num == 2) + b_gender_2[[s]] * (gender_num == 1)
V_2[["alt_4"]] = asc_4_2[[s]]

mnl_settings_2$utilities = V_2
mnl_settings_2$componentName = paste0("model2_Class_",s)

### Compute within-class choice probabilities using MNL model
P[[paste0("model2_Class_",s)]] = apollo_mnl(mnl_settings_2, functionality)

}

Re: LCCM model with two choice models

Posted: 21 Mar 2022, 18:28
by stephanehess
Hi

could you please post the entire apollo_probabilities function for your example?

Thanks

Stephane

Re: LCCM model with two choice models

Posted: 22 Mar 2022, 06:36
by jaimlk77
Hi

Please see the entire apollo_probabilities below.

Thanks,
Jai

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()

### List of utilities: these must use the same names as in mnl_settings, order is irrelevant
V_1 = list()

### Define settings for MNL model component
mnl_settings_1 = list(
alternatives = c(alt_1 = 1, alt_2 = 2, alt_3 = 3, alt_4 = 4),
avail = list(alt_1 = 1, alt_2 = 1, alt_3 = 1, alt_4 = 1),
choiceVar = actual_veh_change_fall19_fall20)

### Define settings for MNL model component
mnl_settings_2 = list(
alternatives = c(alt_1 = 1, alt_2 = 2, alt_3 = 3, alt_4 = 4),
avail = list(alt_1 = 1, alt_2 = 1, alt_3 = 1, alt_4 = 1),
choiceVar = expect_change_fall20_summer20)
### Loop over classes
for(s in 1:2){

### Compute class-specific utilities
V_1[["alt_1"]] = asc_1_1[[s]] + b_age_num_1_1[[s]] * (age_num == 1) + b_age_num_2_1[[s]] * (age_num == 2) + b_gender_1[[s]] * (gender_num == 1)
V_1[["alt_2"]] = asc_2_1[[s]] + b_age_num_1_1[[s]] * (age_num == 1) + b_age_num_2_1[[s]] * (age_num == 2) + b_gender_1[[s]] * (gender_num == 1)
V_1[["alt_3"]] = asc_3_1[[s]] + b_age_num_1_1[[s]] * (age_num == 1) + b_age_num_2_1[[s]] * (age_num == 2) + b_gender_1[[s]] * (gender_num == 1)
V_1[["alt_4"]] = asc_4_1[[s]]

mnl_settings_1$utilities = V_1
mnl_settings_1$componentName = paste0("model1_Class_",s)

### Compute within-class choice probabilities using MNL model
P[[paste0("model1_Class_",s)]] = apollo_mnl(mnl_settings_1, functionality)

V_2 = list()

V_2[["alt_1"]] = asc_1_2[[s]] + b_age_num_1_2[[s]] * (age_num == 1) + b_age_num_2_2[[s]] * (age_num == 2) + b_gender_2[[s]] * (gender_num == 1)
V_2[["alt_2"]] = asc_2_2[[s]] + b_age_num_1_2[[s]] * (age_num == 1) + b_age_num_2_2[[s]] * (age_num == 2) + b_gender_2[[s]] * (gender_num == 1)
V_2[["alt_3"]] = asc_3_2[[s]] + b_age_num_1_2[[s]] * (age_num == 1) + b_age_num_2_2[[s]] * (age_num == 2) + b_gender_2[[s]] * (gender_num == 1)
V_2[["alt_4"]] = asc_4_2[[s]]

mnl_settings_2$utilities = V_2
mnl_settings_2$componentName = paste0("model2_Class_",s)

### Compute within-class choice probabilities using MNL model
P[[paste0("model2_Class_",s)]] = apollo_mnl(mnl_settings_2, functionality)

}

### Compute latent class model probabilities
lc_settings = list(inClassProb = P, classProb=pi_values)


P[["lc_model"]] = apollo_lc(lc_settings, apollo_inputs, functionality)
### Take product across observation for same individual
# P = apollo_panelProd(P, apollo_inputs, functionality)

#P = apollo_combineModels(P, apollo_inputs, functionality)

### Prepare and return outputs of function
P = apollo_prepareProb(P, apollo_inputs, functionality)
return(P)
}

Re: LCCM model with two choice models

Posted: 22 Mar 2022, 10:19
by stephanehess
Hi

you'll need to call apollo_combineModels inside the loop over classes, so that your two MNL models are combined inside the class.

But I think you also need to change some names for that to work. Can you try the following:

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()

### List of utilities: these must use the same names as in mnl_settings, order is irrelevant
V_1 = list()

### Define settings for MNL model component
mnl_settings_1 = list(
alternatives = c(alt_1 = 1, alt_2 = 2, alt_3 = 3, alt_4 = 4),
avail = list(alt_1 = 1, alt_2 = 1, alt_3 = 1, alt_4 = 1),
choiceVar = actual_veh_change_fall19_fall20)

### Define settings for MNL model component
mnl_settings_2 = list(
alternatives = c(alt_1 = 1, alt_2 = 2, alt_3 = 3, alt_4 = 4),
avail = list(alt_1 = 1, alt_2 = 1, alt_3 = 1, alt_4 = 1),
choiceVar = expect_change_fall20_summer20)
### Loop over classes
for(s in 1:2){

P_temp=list()

### Compute class-specific utilities
V_1[["alt_1"]] = asc_1_1[[s]] + b_age_num_1_1[[s]] * (age_num == 1) + b_age_num_2_1[[s]] * (age_num == 2) + b_gender_1[[s]] * (gender_num == 1)
V_1[["alt_2"]] = asc_2_1[[s]] + b_age_num_1_1[[s]] * (age_num == 1) + b_age_num_2_1[[s]] * (age_num == 2) + b_gender_1[[s]] * (gender_num == 1)
V_1[["alt_3"]] = asc_3_1[[s]] + b_age_num_1_1[[s]] * (age_num == 1) + b_age_num_2_1[[s]] * (age_num == 2) + b_gender_1[[s]] * (gender_num == 1)
V_1[["alt_4"]] = asc_4_1[[s]]

mnl_settings_1$utilities = V_1
mnl_settings_1$componentName = paste0("model1_Class_",s)

### Compute within-class choice probabilities using MNL model
P_temp[[paste0("model1_Class_",s)]] = apollo_mnl(mnl_settings_1, functionality)

V_2 = list()

V_2[["alt_1"]] = asc_1_2[[s]] + b_age_num_1_2[[s]] * (age_num == 1) + b_age_num_2_2[[s]] * (age_num == 2) + b_gender_2[[s]] * (gender_num == 1)
V_2[["alt_2"]] = asc_2_2[[s]] + b_age_num_1_2[[s]] * (age_num == 1) + b_age_num_2_2[[s]] * (age_num == 2) + b_gender_2[[s]] * (gender_num == 1)
V_2[["alt_3"]] = asc_3_2[[s]] + b_age_num_1_2[[s]] * (age_num == 1) + b_age_num_2_2[[s]] * (age_num == 2) + b_gender_2[[s]] * (gender_num == 1)
V_2[["alt_4"]] = asc_4_2[[s]]

mnl_settings_2$utilities = V_2
mnl_settings_2$componentName = paste0("model2_Class_",s)

### Compute within-class choice probabilities using MNL model
P_temp[[paste0("model2_Class_",s)]] = apollo_mnl(mnl_settings_2, functionality)

P[[paste0("Class_",s)]] = apollo_combineModels(P_temp,functionality)

}

### Compute latent class model probabilities
lc_settings = list(inClassProb = P, classProb=pi_values)


P[["lc_model"]] = apollo_lc(lc_settings, apollo_inputs, functionality)
### Take product across observation for same individual
P = apollo_panelProd(P, apollo_inputs, functionality)

#P = apollo_combineModels(P, apollo_inputs, functionality)

### Prepare and return outputs of function
P = apollo_prepareProb(P, apollo_inputs, functionality)
return(P)
}
Re: LCCM model with two choice models
by stephanehess » Mon Mar 21, 2022 7:28 pm

Hi

could you please post the entire apollo_probabilities function for your example?

Thanks

Stephane
LCCM model with two choice models
by jaimlk77 » Fri Mar 18, 2022 6:12 pm

Hi

I am trying to estimate a LCCM with two choice models in each latent class. Is that possible to estimate in Apollo?

As shown in the attached subset of the R code. I am trying to wrap two MNLs in latent classes. However, I keep getting the following error:

Error in apollo_lc(lc_settings, apollo_inputs, functionality) :
Arguments 'inClassProb' and 'classProb' for model component "LC" must have the same length.

I thought using the apollo_combineModels would resolve this issue but that did not help. Does anyone have any suggestions on how I can resolve this issue?

Thanks,
Jai




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

### Compute class-specific utilities
V_1[["alt_1"]] = asc_1_1[[s]] + b_age_num_1_1[[s]] * (age_num == 1) + b_age_num_2_1[[s]] * (age_num == 2) + b_gender_1[[s]] * (gender_num == 1)
V_1[["alt_2"]] = asc_2_1[[s]] + b_age_num_1_1[[s]] * (age_num == 1) + b_age_num_2_1[[s]] * (age_num == 2) + b_gender_1[[s]] * (gender_num == 1)
V_1[["alt_3"]] = asc_3_1[[s]] + b_age_num_1_1[[s]] * (age_num == 1) + b_age_num_2_1[[s]] * (age_num == 2) + b_gender_1[[s]] * (gender_num == 1)
V_1[["alt_4"]] = asc_4_1[[s]]

mnl_settings_1$utilities = V_1
mnl_settings_1$componentName = paste0("model1_Class_",s)

### Compute within-class choice probabilities using MNL model
P[[paste0("model1_Class_",s)]] = apollo_mnl(mnl_settings_1, functionality)

V_2 = list()

V_2[["alt_1"]] = asc_1_2[[s]] + b_age_num_1_2[[s]] * (age_num == 1) + b_age_num_2_2[[s]] * (age_num == 2) + b_gender_2[[s]] * (gender_num == 1)
V_2[["alt_2"]] = asc_2_2[[s]] + b_age_num_1_2[[s]] * (age_num == 1) + b_age_num_2_2[[s]] * (age_num == 2) + b_gender_2[[s]] * (gender_num == 1)
V_2[["alt_3"]] = asc_3_2[[s]] + b_age_num_1_2[[s]] * (age_num == 1) + b_age_num_2_2[[s]] * (age_num == 2) + b_gender_2[[s]] * (gender_num == 1)
V_2[["alt_4"]] = asc_4_2[[s]]

mnl_settings_2$utilities = V_2
mnl_settings_2$componentName = paste0("model2_Class_",s)

### Compute within-class choice probabilities using MNL model
P[[paste0("model2_Class_",s)]] = apollo_mnl(mnl_settings_2, functionality)

}

Re: LCCM model with two choice models

Posted: 03 Feb 2023, 15:30
by punyabeet
Hi Prof Stephane

Thanks for the apollo forum. I tried to estimate LCCM with two choice models in each latent class with a similar specification as above. However, I keep getting the following error:

Error in apollo_validate(classAlloc_settings, modelType, functionality, :
Some of the names of the classes for model component 'classAlloc' do not match!

I think I have made an error in defining the latent class components. Can you please point out the mistake in the R code snippet?

# ################################################################# #
#### DEFINE MODEL PARAMETERS ####
# ################################################################# #

### Vector of parameters, including any that are kept fixed in estimation
apollo_beta = c(asc_1_1 = 0,
asc_2_1 = 0,
asc_3_1 = 0,
asc_1_2 = 0,
asc_2_2 = 0,
asc_3_2 = 0,
b_tt_a = 0,
b_tt_b = 0,
delta_a_1 = 0,
delta_a_2 = 0,
delta_b_1 = 0,
delta_b_2 = 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("delta_b_1", "delta_b_2", "asc_3_1", "asc_3_2")

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

apollo_lcPars=function(apollo_beta, apollo_inputs){
lcpars = list()
lcpars[["b_tt_1"]] = list(b_tt_a, b_tt_b)
lcpars[["b_tt_2"]] = list(b_tt_a, b_tt_b)

V_1 = list()
V_1[["class_a"]] = delta_a_1
V_1[["class_b"]] = delta_b_1

V_2 = list()
V_2[["class_a"]] = delta_a_2
V_2[["class_b"]] = delta_b_2


### Settings for class allocation models
classAlloc_settings = list(
classes = c(class_a=1, class_b=2),
utilities = V
)

### Settings for class allocation models
classAlloc_settings = list(
classes = c(class_a = 1, class_b = 2),
utilities = c(V_1, V_2),
avail = 1
)

lcpars[["pi_values"]] = apollo_classAlloc(classAlloc_settings)

return(lcpars)
}

Many thanks for considering my request.
Punya

Re: LCCM model with two choice models

Posted: 28 Feb 2023, 22:38
by dpalma
Hi Punya,

Your code is using two class allocation functions. What I believe you want is a single allocation function, and within each class to have two choices. Below is an example that does so.

The example uses the example database apollo_timeUseData, and it estimates a latent class model with two classes. Within each class, there are two choices: to engage in leasure (yes/no), and to engage in work (yes/no). Each choice has different parameters inside each class. You can try using this structure for your application.

Cheers
David

Code: Select all

# ################################################################# #
#### LOAD LIBRARY AND DEFINE CORE SETTINGS                       ####
# ################################################################# #

### Initialise
rm(list = ls())
library(apollo)
apollo_initialise()

### Set core controls
apollo_control = list(
  modelName       = "LC_twoChoices",
  modelDescr      = "LC models with 2 classes and two choices inside each",
  indivID         = "indivID"
)

# ################################################################# #
#### LOAD DATA AND APPLY ANY TRANSFORMATIONS                     ####
# ################################################################# #

### Loading data from package
### if data is to be loaded from a file (e.g. called data.csv), 
### the code would be: database = read.csv("data.csv",header=TRUE)
database = apollo_timeUseData
### for data dictionary, use ?apollo_timeUseData
# outside good: time spent at home and travelling
database$t_outs = rowSums(database[,c("t_a01", "t_a06", "t_a10", "t_a11", "t_a12")])/60 
database$t_leis = rowSums(database[,c("t_a07", "t_a08", "t_a09")])/60
database$t_work = database$t_a02/60
database$t_scho = database$t_a03/60
database$t_shop = database$t_a04/60
database$t_priv = database$t_a05/60
database$doesLeisure <- database$t_leis > 0
database$doesWork    <- database$t_work > 0

# ################################################################# #
#### DEFINE MODEL PARAMETERS                                     ####
# ################################################################# #

### Vector of parameters, including any that are kept fixed in estimation
apollo_beta = c(ascL_1 = 0, ascL_2 = 0, 
                bFeL_1 = 0, bFeL_2 = 0, 
                bAgL_1 = 0, bAgL_2 = 0, 
                bFTL_1 = 0, bFTL_2 = 0, 
                bWkL_1 = 0, bWkL_2 = 0, 
                ascW_1 = 0, ascW_2 = 0, 
                bFeW_1 = 0, bFeW_2 = 0, 
                bAgW_1 = 0, bAgW_2 = 0, 
                bFTW_1 = 0, bFTW_2 = 0, 
                bWkW_1 = 0, bWkW_2 = 0, 
                delt_1 = 0, delt_2 = 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("delt_2")

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

apollo_lcPars=function(apollo_beta, apollo_inputs){
  lcpars = list()
  lcpars[["ascL"]] = list(ascL_1, ascL_2)
  lcpars[["bFeL"]] = list(bFeL_1, bFeL_2)
  lcpars[["bAgL"]] = list(bAgL_1, bAgL_2)
  lcpars[["bFTL"]] = list(bFTL_1, bFTL_2)
  lcpars[["bWkL"]] = list(bWkL_1, bWkL_2)
  lcpars[["ascW"]] = list(ascW_1, ascW_2)
  lcpars[["bFeW"]] = list(bFeW_1, bFeW_2)
  lcpars[["bAgW"]] = list(bAgW_1, bAgW_2)
  lcpars[["bFTW"]] = list(bFTW_1, bFTW_2)
  lcpars[["bWkW"]] = list(bWkW_1, bWkW_2)
  
  classAlloc_settings = list(
    utilities = list(class_1 = delt_1, 
                     class_2 = delt_2)
  )
  
  lcpars[["pi_values"]] = apollo_classAlloc(classAlloc_settings)
  
  return(lcpars)
}

# ################################################################# #
#### GROUP AND VALIDATE INPUTS                                   ####
# ################################################################# #

apollo_inputs = apollo_validateInputs()

# ################################################################# #
#### DEFINE MODEL AND LIKELIHOOD FUNCTION                        ####
# ################################################################# #

apollo_probabilities=function(apollo_beta, apollo_inputs, functionality="estimate"){
  
  ### Initialise
  apollo_attach(apollo_beta, apollo_inputs)
  on.exit(apollo_detach(apollo_beta, apollo_inputs))
  P = list()
  
  ### Define settings for MNL model component that are generic across classes
  mnl_leisure_settings = list(
    alternatives = c(no=0, yes=1),
    choiceVar    = doesLeisure
  )
  mnl_work_settings = list(
    alternatives = c(no=0, yes=1),
    choiceVar    = doesWork
  )
  
  ### Loop over classes
  for(s in 1:2){
    
    ### Leisure decision within class s
    mnl_leisure_settings$utilities = list(
      no  = 0, 
      yes = ascL[[s]] + bFeL[[s]]*female + bAgL[[s]]*age + bFTL[[s]]*occ_full_time + bWkL[[s]]*weekend
    )
    P[[paste0("Class_",s,"_leisure")]] = apollo_mnl(mnl_leisure_settings, functionality)
    
    ### Work decision within class s
    mnl_work_settings$utilities = list(
      no  = 0, 
      yes = ascW[[s]] + bFeW[[s]]*female + bAgW[[s]]*age + bFTW[[s]]*occ_full_time + bWkW[[s]]*weekend
    )
    P[[paste0("Class_",s,"_work")]] = apollo_mnl(mnl_work_settings, functionality)
    
    ### Take product of both decisions
    P[[paste0("Class_",s)]] = P[[paste0("Class_",s,"_leisure")]]*P[[paste0("Class_",s,"_work")]]
    
    ### Take product across observation for same individual
    P[[paste0("Class_",s)]] = apollo_panelProd(P[[paste0("Class_",s)]], apollo_inputs ,functionality)
  }
  
  ### Compute latent class model probabilities
  lc_settings  = list(inClassProb = P[paste0("Class_",1:2)], 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 ESTIMATION AND OUTPUT                                 ####
# ################################################################# #

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

### Output to screen
apollo_modelOutput(model)

### Output to file
apollo_saveOutput(model)