Page 1 of 1

HCM model with casulity between latent factors

Posted: 06 Jun 2022, 10:44
by Rui_Liu
Currently, I am trying to use the 'Apollo' package to run an HCM simultaneously considering the relationship between latent variables.
I have some questions to consult about the hybrid choice model.
1. Does it is feasible to consider the relationships between different latent factors in “Apollo” package, like SEM.
2. I have tried to run the code in “Apollo” package considering the relationship between latent variables, here, I list the code of the latent model part which defines the association between latent variables.
(i.e., LV_risk and LV_control are predictors of LV_pro, except for personal socio-demographics). From the perspective of model estimation, the code works well and produces good results.
So, I would like to request your help to confirm that it is correct to define the relationships between latent variables in this way.

### Create random parameters
apollo_randCoeff=function(apollo_beta, apollo_inputs){
randcoeff = list()

randcoeff[["LV_risk"]] = gamma_gender_risk * gender + gamma_age_risk * age60 + gamma_householdsizes_risk * householdsizes + gamma_education_risk * educationlevels_12 + eta_risk
randcoeff[["LV_control"]] = gamma_gender_control * gender + gamma_age_control * age60 + gamma_householdsizes_control * householdsizes + gamma_education_control * educationlevels_12 + eta_control
randcoeff[["LV_pro"]] = gamma_gender_pro * gender + gamma_age_pro * age60 + gamma_householdsizes_pro * householdsizes + gamma_education_pro * educationlevels_12 + eta_pro
+ theta_risk * (gamma_gender_risk * gender + gamma_age_risk * age60 + gamma_householdsizes_risk * householdsizes + gamma_education_risk * educationlevels_12 + eta_risk)
+ theta_control * (gamma_gender_control * gender + gamma_age_control * age60 + gamma_householdsizes_control * householdsizes + gamma_education_control * educationlevels_12 + eta_control)

return(randcoeff)
}

Looking forward to your kindly reply.

Sincerely yours
Rui Liu

Re: HCM model with casulity between latent factors

Posted: 27 Jun 2022, 11:45
by stephanehess
Hi

apologies for the slow reply.

could you share the rest of the code too, please?

Thanks

Stephane

Re: HCM model with casulity between latent factors

Posted: 01 Jul 2022, 02:37
by Rui_Liu
Hello, Pro. Stephane.
Thanks for your reply.
I have posted the whole code, so please kindly check it.

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

### set work directory ###
setwd('C:/download/data analysis software/data analysis/R/practice/social contact/final/result/result_verify/asc_chioce_latent_no_gender_age_PMT_cost_3_new/')

### Clear memory
rm(list = ls())

### Load Apollo library
library(apollo)

### Initialise code
apollo_initialise()

### Set core controls
apollo_control = list(
modelName = "2_Hybird_model",
modelDescr = "social contact",
indivID = "id",
mixing = TRUE,
nCores = 14
)

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

database <- read.csv('C:/download/data analysis software/data analysis/R/practice/social contact/mydata_combine_1.csv',fileEncoding = 'GBK',header=TRUE)
database$choice <- database$B10r11

database <-database[complete.cases(database[1614]),]

### combining householdsizes 6+ into 6
database$householdsizes[which(database$householdsizes>=6)] <- 6

### combining both and physical contact_during
database$choice[which(database$choice==4)] <- 3

### combining both and physical contact_before
database$B10r2[which(database$B10r2==4)] <- 3

### substitute NA_before by 0
database$B10r2[is.na(database$B10r2)] <- 0

### Subtract mean of indicator variables to centre them on zero

########### Part C ##############
#### Threat appraisal ####
database$C3r1 = database$C3r1 - mean(database$C3r1)
database$C3r3 = database$C3r3 - mean(database$C3r3)
database$C3r4 = database$C3r4 - mean(database$C3r4)

#### Coping appraisal ####
database$C4r1 = database$C4r1 - mean(database$C4r1)
database$C4r4 = database$C4r4 - mean(database$C4r4)
database$C4r5 = database$C4r5 - mean(database$C4r5)

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

apollo_beta = c(
asc_phy = 0,
asc_nonphy = 0,
b_travelparty_other_phy = 0,
b_travelparty_other_nonphy = 0,
b_duration_phy = 0,
b_duration_nonphy = 0,
b_past_no_phy = 0,
b_past_nonphy_phy = 0,
b_past_phy_phy = 0,
b_past_no_nonphy = 0,
b_past_nonphy_nonphy = 0,
b_past_phy_nonphy = 0,
b_3cs2_phy = 0,
b_3cs2_nonphy = 0,
lambda_risk_phy = 0,
lambda_risk_nonphy = 0,
lambda_control_phy = 0,
lambda_control_nonphy = 0,
lambda_pro_phy = 0,
lambda_pro_nonphy = 0,
gamma_gender_risk = 0,
gamma_age_risk = 0,
gamma_education_risk = 0,
gamma_householdsizes_risk = 0,
gamma_gender_control = 0,
gamma_age_control = 0,
gamma_education_control = 0,
gamma_householdsizes_control = 0,
gamma_gender_pro = 0,
gamma_age_pro = 0,
gamma_education_pro = 0,
gamma_householdsizes_pro = 0,
zeta_risk_1 = 1,
zeta_risk_2 = 1,
zeta_risk_3 = 1,
zeta_control_1 = 1,
zeta_control_2 = 1,
zeta_control_3 = 1,
zeta_pro_1 = 1,
zeta_pro_2 = 1,
zeta_pro_3 = 1,
sigma_risk_1 = 1,
sigma_risk_2 = 1,
sigma_risk_3 = 1,
sigma_control_1 = 1,
sigma_control_2 = 1,
sigma_control_3 = 1,
theta_risk = 0,
theta_control = 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('b_past_no_phy','b_past_no_nonphy')

# ################################################################# #
#### DEFINE RANDOM COMPONENTS ####
# ################################################################# #

### Set parameters for generating draws
apollo_draws = list(
interDrawsType="halton",
interNDraws=100,
interUnifDraws=c(),
interNormDraws=c('eta_risk','eta_control','eta_pro'),

intraDrawsType='',
intraNDraws=0,
intraUnifDraws=c(),
intraNormDraws=c()
)

### Create random parameters
apollo_randCoeff=function(apollo_beta, apollo_inputs){
randcoeff = list()

randcoeff[["LV_risk"]] = gamma_gender_risk * gender + gamma_age_risk * age60 + gamma_householdsizes_risk * householdsizes + gamma_education_risk * educationlevels_12 + eta_risk
randcoeff[["LV_control"]] = gamma_gender_control * gender + gamma_age_control * age60 + gamma_householdsizes_control * householdsizes + gamma_education_control * educationlevels_12 + eta_control
randcoeff[["LV_pro"]] = gamma_gender_pro * gender + gamma_age_pro * age60 + gamma_householdsizes_pro * householdsizes + gamma_education_pro * educationlevels_12 + eta_pro + theta_risk * (gamma_gender_risk * gender + gamma_age_risk * age60 + gamma_householdsizes_risk * householdsizes + gamma_education_risk * educationlevels_12 + eta_risk) + theta_control * (gamma_gender_control * gender + gamma_age_control * age60 + gamma_householdsizes_control * householdsizes + gamma_education_control * educationlevels_12 + eta_control)

return(randcoeff)
}

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

apollo_inputs = apollo_validateInputs()

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

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

### Likelihood of indicators

normalDensity_settings1 = list(outcomeNormal = C3r1,
xNormal = zeta_risk_1*LV_risk,
mu = 0,
sigma = sigma_risk_1,
componentName = "indic_risk_1")
normalDensity_settings2 = list(outcomeNormal = C3r3,
xNormal = zeta_risk_2*LV_risk,
mu = 0,
sigma = sigma_risk_2,
componentName = "indic_risk_2")
normalDensity_settings3 = list(outcomeNormal = C3r4,
xNormal = zeta_risk_3*LV_risk,
mu = 0,
sigma = sigma_risk_3,
componentName = "indic_risk_3")
normalDensity_settings4 = list(outcomeNormal = C4r2,
xNormal = zeta_control_1*LV_control,
mu = 0,
sigma = sigma_control_1,
componentName = "indic_control_1")
normalDensity_settings5 = list(outcomeNormal = C4r4,
xNormal = zeta_control_2*LV_control,
mu = 0,
sigma = sigma_control_2,
componentName = "indic_control_2")
normalDensity_settings6 = list(outcomeNormal = C4r5,
xNormal = zeta_control_3*LV_control,
mu = 0,
sigma = sigma_control_3,
componentName = "indic_control_3")

V = list()
V[['no_mask']] = 0
V[['yes_mask']] = zeta_pro_1 * LV_pro
mnl_settings1 = list(
alternatives = c(no_mask=0, yes_mask=1),
avail = list(no_mask=1,yes_mask=1),
choiceVar = B13r11c1,
V = V,
componentName = "indic_pro_1")
V = list()
V[['no_disinfect']] = 0
V[['yes_disinfect']] = zeta_pro_2 * LV_pro
mnl_settings2 = list(
alternatives = c(no_disinfect=0, yes_disinfect=1),
avail = list(no_disinfect=1,yes_disinfect=1),
choiceVar = B13r11c2,
V = V,
componentName = "indic_pro_2")

V = list()
V[['no_touch']] = 0
V[['yes_touch']] = zeta_pro_3 * LV_pro
mnl_settings3 = list(
alternatives = c(no_touch=0, yes_touch=1),
avail = list(no_touch=1,yes_touch=1),
choiceVar = B13r11c4,
V = V,
componentName = "indic_pro_3")

P[["indic_risk_1"]] = apollo_normalDensity(normalDensity_settings1, functionality)
P[["indic_risk_2"]] = apollo_normalDensity(normalDensity_settings2, functionality)
P[["indic_risk_3"]] = apollo_normalDensity(normalDensity_settings3, functionality)
P[["indic_control_1"]] = apollo_normalDensity(normalDensity_settings4, functionality)
P[["indic_control_2"]] = apollo_normalDensity(normalDensity_settings5, functionality)
P[["indic_control_3"]] = apollo_normalDensity(normalDensity_settings6, functionality)
P[["indic_pro_1"]] = apollo_mnl(mnl_settings1, functionality)
P[["indic_pro_2"]] = apollo_mnl(mnl_settings2, functionality)
P[["indic_pro_3"]] = apollo_mnl(mnl_settings3, functionality)

### Likelihood of choices
### List of utilities: these must use the same names as in mnl_settings, order is irrelevant
V = list()
V[['nocon']] = 0
V[['phy']] = ( asc_phy
+ b_travelparty_other_phy * cmtravelparty_amusementparks_during
+ b_duration_phy * B7r11
+ b_past_no_phy * (B10r2==1)
+ b_past_nonphy_phy * (B10r2==2)
+ b_past_phy_phy * (B10r2==3)
+ b_3cs2_phy * B12r11c2
+ lambda_risk_phy * LV_risk
+ lambda_control_phy * LV_control
+ lambda_pro_phy * LV_pro)
V[['nonphy']] = ( asc_nonphy
+ b_travelparty_other_nonphy * cmtravelparty_amusementparks_during
+ b_duration_nonphy * B7r11
+ b_past_no_nonphy * (B10r2==1)
+ b_past_nonphy_nonphy * (B10r2==2)
+ b_past_phy_nonphy * (B10r2==3)
+ b_3cs2_nonphy * B12r11c2
+ lambda_risk_nonphy * LV_risk
+ lambda_control_nonphy * LV_control
+ lambda_pro_nonphy * LV_pro)

### Define settings for MNL model component
mnl_settings = list(
alternatives = c(nocon=1, nonphy=2, phy=3),
avail = list(nocon=1, nonphy=1, phy=1),
choiceVar = choice,
V = V
)

### Compute probabilities for MNL model component
P[["choice"]] = apollo_mnl(mnl_settings, functionality)

### Likelihood of the whole model
P = apollo_combineModels(P, apollo_inputs, functionality)

### Average across inter-individual draws
P = apollo_avgInterDraws(P, apollo_inputs, functionality)

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

# ################################################################# #
#### MODEL ESTIMATION ####
# ################################################################# #

### Optional: calculate LL before model estimation
apollo_llCalc(apollo_beta, apollo_probabilities, apollo_inputs)

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

# ################################################################# #
#### MODEL OUTPUTS ####
# ################################################################# #

# ----------------------------------------------------------------- #
#---- FORMATTED OUTPUT (TO SCREEN) ----
# ----------------------------------------------------------------- #

apollo_modelOutput(model, modelOutput_settings = list(printPVal=2))

# ----------------------------------------------------------------- #
#---- FORMATTED OUTPUT (TO FILE, using model name) ----
# ----------------------------------------------------------------- #

apollo_saveOutput(model, saveOutput_settings = list(printPVal=2))


Looking forward to your reply.
Best regards
Rui

Re: HCM model with casulity between latent factors

Posted: 19 Jul 2022, 10:20
by dpalma
Hi Rui,

You code looks correct.

A shorter way to write the interrelation between latent variables is as follows. Apollo should be smart enough to replace the latent variables by their definitions by itself.

Code: Select all

### Create random parameters
apollo_randCoeff=function(apollo_beta, apollo_inputs){
  randcoeff = list()
  
  randcoeff[["LV_risk"]]    = gamma_gender_risk * gender + gamma_age_risk * age60 + gamma_householdsizes_risk * householdsizes + gamma_education_risk * educationlevels_12 + eta_risk
  randcoeff[["LV_control"]] = gamma_gender_control * gender + gamma_age_control * age60 + gamma_householdsizes_control * householdsizes + gamma_education_control * educationlevels_12 + eta_control
  randcoeff[["LV_pro"]]     = gamma_gender_pro * gender + gamma_age_pro * age60 + gamma_householdsizes_pro * householdsizes + gamma_education_pro * educationlevels_12 + eta_pro + theta_risk * randcoeff[["LV_risk"]] + theta_control * randcoeff[["LV_control"]]
  
  return(randcoeff)
}
Best wishes
David

Re: HCM model with casulity between latent factors

Posted: 19 Jul 2022, 10:54
by Rui_Liu
Hi David,

Thanks for your kind reply.
It helps a lot. Then I can use the code in the data analysis part of my research.

Best wishes
Rui Liu

Re: HCM model with casulity between latent factors

Posted: 22 Nov 2022, 19:56
by ha.ortiz10
Hi all

I see that risk, control, and pro, all are parameters in the Utility function, i.e.:

... + lambda_risk_nonphy * LV_risk + lambda_control_nonphy * LV_control + lambda_pro_nonphy * LV_pro)

But, then, you would be including direct and indirect effects of risk and control over the utility... How would you proceed if you want to test only indirect effects? That is... if you wanted to test only the effect of PRO on the utility function (considering that pro is explained by risk and control) would you just not include this part "+ lambda_risk_nonphy * LV_risk + lambda_control_nonphy * LV_control" on the utility function? Does it make sense...

Excuse me if this is a super dumb question.

Re: HCM model with casulity between latent factors

Posted: 25 Nov 2022, 16:10
by dpalma
Hi,

I am not an expert in Structural Equation Modelling, but my understanding is that a given factor can have both direct and indirect effects in an outcome (the choice, in this case), without causing issue. In this case factors "risk" and "control" both influence "pro", and all three influence the utility of the choice. So the the structure is:

Code: Select all

risk ----> pro <--- control
 \         |          /
  \        v         /
   ---> U_choice <---
  • The indirect effect of risk on the choice utility would be theta_risk * lambda_pro
  • The direct effect of risk on the choice utility would be lambda_risk
  • The indirect effect of control on the choice utility would be theta_control * lambda_pro
  • The direct effect of control on the choice utility would be lambda_control
  • The direct effect of pro on the choice utility would be lambda_pro

Even if you are interested only in the indirect effect of risk and control, it might be useful to test the full model, and only discard the direct effects of risk and control if lambda_risk and lambda_control are not significant. Only if you have strong theoretical reasons to assume those should be zero, then you can go straight for a model where you fix lambda_risk and lambda_control to zero.

Cheers
David

Re: HCM model with casulity between latent factors

Posted: 09 Sep 2025, 11:30
by gabystephanie
Hi David,
I am sorry for bringing this thread back to life again because I really need your help.

I have a question, if i have this structure, and i want to estimate the indirect effect of BP on the choice utility, and the moderating effect of SC on BP influence on the choice utility.

Code: Select all

X ----> BP -
 \         |   <--- SC
  \        v         
   ---> U_choice 
   
and i have this in my code, do you think i have entered the estimation correctly? thank you so much

Code: Select all

 
 apollo_control = list(
  modelName       = "HCM241_1207",  # or any name you like
  modelDescr      = "Hybrid Choice Model for trust in green hotels",
  indivID         = "ID",                 # replace with your actual respondent ID column
  mixing          = TRUE,
  nCores          = 7)                 # or more, depending on your machine
 apollo_beta = c (lambda_BP = 0.5, lambda_BP_SC = 0.5, asc_1=0, asc_2=0,
  zeta_BP_1 = 0.54592, zeta_BP_2 = 0.46008, zeta_BP_3 = 0.31626, zeta_BP_4 = 0.51507,
  zeta_BP_5 = 0.54111, zeta_BP_6 = 0.38038, zeta_BP_7 = 0.47925,
  zeta_SC_1 = 0.35201, zeta_SC_2 = 0.31958, zeta_SC_3 = 0.83219, zeta_SC_4 = 0.74095,
  sigma_BP1 = 1, sigma_BP2 = 1, sigma_BP3 = 1, sigma_BP4 = 1,sigma_BP5 = 1, sigma_BP6 = 1,sigma_BP7 = 1,
  sigma_SC1 = 1, sigma_SC2 = 1, sigma_SC3 = 1, sigma_SC4 = 1, 
  gamma_SC_univ = 0, gamma_SC_reason = 0, gamma_SC_age = 0, gamma_BP_univ = 0, gamma_BP_reason = 0, gamma_BP_age = 0,
  mu_HT2    = 0.24795, mu_HT3    = 0.18591, sigma_HT2 =  0.2,
  sigma_HT3 =  0.97914, # Use abs(3.1) if you had a valid positive estimate
  mu_GM2    = 0.68164, mu_GM3    = 0.57952,
  sigma_GM2 =  0.71102,  sigma_GM3 =  0.4,
  mu_TC2    =  1.07, mu_TC3    =  1.42985, theta_HT=0, theta_GM=0, theta_TC=0,
  sigma_TC2 =  0.83871, sigma_TC3 =  0.98561)
	

### 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("asc_2")

# ################################################################# #
#### DEFINE RANDOM COMPONENTS                                    ####
# ################################################################# #

### Set parameters for generating draws
apollo_draws = list(
  interDrawsType = "sobol", 
  interNDraws    = 2000,          
  interNormDraws = c("eta_BP", "eta_SC", "draws_HT3","draws_HT2", "draws_GM2","draws_GM3", "draws_TC2", "draws_TC3")
)

### Create random parameters
apollo_randCoeff = function(apollo_beta, apollo_inputs){
  randcoeff = list()
  randcoeff[["b_HT2"]] = mu_HT2 + sigma_HT2 * draws_HT2 
  randcoeff[["b_HT3"]] = mu_HT3 + sigma_HT3 * draws_HT3  
  randcoeff[["b_GM2"]] = mu_GM2 + sigma_GM2 * draws_GM2
  randcoeff[["b_GM3"]] = mu_GM3 + sigma_GM3 * draws_GM3 
  randcoeff[["b_TC2"]] = mu_TC2 + sigma_TC2 * draws_TC2
  randcoeff[["b_TC3"]] = mu_TC3 + sigma_TC3 * draws_TC3
randcoeff[["BP"]] = gamma_BP_univ*Education + gamma_BP_reason*Reason + gamma_BP_age*Age + eta_BP + theta_HT*randcoeff[["b_HT2"]] + theta_HT*randcoeff[["b_HT3"]] +  
theta_GM*randcoeff[["b_GM2"]] + theta_GM*randcoeff[["b_GM3"]]+ theta_TC*randcoeff[["b_TC2"]] + theta_HT*randcoeff[["b_TC3"]]
randcoeff[["SC"]] = gamma_SC_univ*Education + gamma_SC_reason*Reason + gamma_SC_age*Age + eta_SC 

return(randcoeff)
}

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

apollo_inputs = apollo_validateInputs()

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

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

  ### Likelihood of indicators
  normalDensity_settings1 = list(outcomeNormal = BP_1, 
                      xNormal        = zeta_BP_1*BP, 
                      mu            = 0,
                      sigma		= sigma_BP1,
			    rows           = (task==1),
			    componentName = "indic_BP_1")
			    
			  
  normalDensity_settings2 = list(outcomeNormal = BP_2, 
                      xNormal        = zeta_BP_2*BP, 
                     mu            = 0,
                      sigma		= sigma_BP2,
			    rows           = (task==1),
			    componentName = "indic_BP_2")
  normalDensity_settings3 = list(outcomeNormal = BP_3, 
                      xNormal        = zeta_BP_3*BP, 
                      mu            = 0,
                      sigma		= sigma_BP3,
			    rows           = (task==1),
			    componentName = "indic_BP_3")
  normalDensity_settings4 = list(outcomeNormal = BP_4, 
                      xNormal        = zeta_BP_4*BP, 
                      mu            = 0,
                      sigma		= sigma_BP4,
			    rows           = (task==1),
			    componentName = "indic_BP_4")

  normalDensity_settings5 = list(outcomeNormal = BP_5, 
                      xNormal        = zeta_BP_5*BP, 
                      mu            = 0,
                      sigma		= sigma_BP5,
			    rows           = (task==1),
			    componentName = "indic_BP_5")

  normalDensity_settings6 = list(outcomeNormal = BP_6, 
                      xNormal        = zeta_BP_6*BP, 
                      mu            = 0,
                      sigma		= sigma_BP6,
			    rows           = (task==1),
			    componentName = "indic_BP_6")

  normalDensity_settings7 = list(outcomeNormal = BP_7, 
                      xNormal        = zeta_BP_7*BP, 
                      mu            = 0,
                      sigma		= sigma_BP7,
			    rows           = (task==1),
			    componentName = "indic_BP_7")
  normalDensity_settings8 = list(outcomeNormal = SC_1, 
                      xNormal        = zeta_SC_1*SC, 
                      mu            = 0,
                      sigma		= sigma_SC1,
			    rows           = (task==1),
			    componentName = "indic_SC_1")

  normalDensity_settings9 = list(outcomeNormal = SC_2, 
                      xNormal        = zeta_SC_2*SC, 
                      mu            = 0,
                      sigma		= sigma_SC2,
			    rows           = (task==1),
			    componentName = "indic_SC_2")
  normalDensity_settings10 = list(outcomeNormal = SC_3, 
                      xNormal        = zeta_SC_3*SC, 
                      mu            = 0,
                      sigma		= sigma_SC3,
			    rows           = (task==1),
			    componentName = "indic_SC_3")
  normalDensity_settings11 = list(outcomeNormal = SC_4, 
                      xNormal        = zeta_SC_4*SC, 
                      mu            = 0,
                      sigma		= sigma_SC4,
			    rows           = (task==1),
			    componentName = "indic_SC_4")

 P[["indic_BP_1"]]=apollo_normalDensity(normalDensity_settings1, functionality)
 P[["indic_BP_1"]] = apollo_panelProd(P[["indic_BP_1"]]    , apollo_inputs, functionality)
 P[["indic_BP_2"]] = apollo_normalDensity(normalDensity_settings2, functionality)
 P[["indic_BP_2"]] = apollo_panelProd(P[["indic_BP_2"]], apollo_inputs, functionality)
 P[["indic_BP_3"]] = apollo_normalDensity(normalDensity_settings3, functionality)
 P[["indic_BP_3"]] = apollo_panelProd(P[["indic_BP_3"]], apollo_inputs, functionality)
 P[["indic_BP_4"]] = apollo_normalDensity(normalDensity_settings4, functionality)
 P[["indic_BP_4"]] = apollo_panelProd(P[["indic_BP_4"]]  , apollo_inputs, functionality)
 P[["indic_BP_5"]] = apollo_normalDensity(normalDensity_settings5, functionality)
 P[["indic_BP_5"]] = apollo_panelProd(P[["indic_BP_5"]]    , apollo_inputs, functionality)
 P[["indic_BP_6"]] = apollo_normalDensity(normalDensity_settings6, functionality)
 P[["indic_BP_6"]] = apollo_panelProd(P[["indic_BP_6"]], apollo_inputs, functionality)
 P[["indic_BP_7"]] = apollo_normalDensity(normalDensity_settings7, functionality)
 P[["indic_BP_7"]] = apollo_panelProd(P[["indic_BP_7"]], apollo_inputs, functionality)
 P[["indic_SC_1"]] = apollo_normalDensity(normalDensity_settings8, functionality)
 P[["indic_SC_1"]] = apollo_panelProd(P[["indic_SC_1"]]    , apollo_inputs, functionality)
 P[["indic_SC_2"]] = apollo_normalDensity(normalDensity_settings9, functionality)
 P[["indic_SC_2"]] = apollo_panelProd(P[["indic_SC_2"]], apollo_inputs, functionality)
 P[["indic_SC_3"]] = apollo_normalDensity(normalDensity_settings10, functionality)
 P[["indic_SC_3"]] = apollo_panelProd(P[["indic_SC_3"]], apollo_inputs, functionality)
 P[["indic_SC_4"]] = apollo_normalDensity(normalDensity_settings11, functionality)
 P[["indic_SC_4"]] = apollo_panelProd(P[["indic_SC_4"]]  , apollo_inputs, functionality)
 
  ### Likelihood of choices
  ### List of utilities: these must use the same names as in mnl_settings, order is irrelevant
  V = list()
 V[['alt1']] = (asc_1 + b_HT2*(HT_1=="2") + b_HT3*(HT_1=="3") + b_GM2*(GM_1=="2") + b_GM3*(GM_1=="3")+ b_TC2*(TC_1=="2") + b_TC3*(TC_1=="3")+lambda_BP*BP+lambda_BP_SC*BP*SC)     
 V[['alt2']] =(asc_2 + b_HT2*(HT_2=="2") + b_HT3*(HT_2=="3") + b_GM2*(GM_2=="2") + b_GM3*(GM_2=="3")+ b_TC2*(TC_2=="2") + b_TC3*(TC_2=="3")+lambda_BP*BP+lambda_BP_SC*BP*SC) 
   
  
  ### Define settings for MNL model component
  mnl_settings = list(
    alternatives = c(alt1=1, alt2=2),
    avail        = list(alt1=1, alt2=1),
    choiceVar    = choice,
    V    = V
  )
  
  ### Compute probabilities for MNL model component
  P[["choice"]] = apollo_mnl(mnl_settings, functionality)
  P[["choice"]] = apollo_panelProd(P[["choice"]], apollo_inputs, functionality)

  ### Average across inter-individual draws
  P = apollo_avgInterDraws(P, apollo_inputs, functionality)

  ### Likelihood of the whole model
  P = apollo_combineModels(P, apollo_inputs, functionality)
  
  ### Prepare and return outputs of function
  P = apollo_prepareProb(P, apollo_inputs, functionality)
  return(P)
}

### Estimate model
model = apollo_estimate(apollo_beta, apollo_fixed, apollo_probabilities, apollo_inputs,
estimate_settings=list(estimationRoutine="bfgs", maxIterations=100000)) 


Re: HCM model with casulity between latent factors

Posted: 23 Sep 2025, 08:15
by dpalma
Hi Gaby,

The code looks good to me. So I think from a theoretical perspective you are good. From a practical perspective, the formulation may be difficult to estimate.

Personally, I do not recall ever estimating a model with mediating effects for (interaction between) latent variables, so I do not know how difficult or easy it is for the model to converge in practice. My guess is it might give you some trouble. So I would begin by estimating the model without the mediating effect, and then using those estimates as starting values for estimating the full model (i.e. with the interaction between latent variables).

Best wishes,
David