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