-
Notifications
You must be signed in to change notification settings - Fork 7
/
plssem_mi.ado
344 lines (316 loc) · 10.4 KB
/
plssem_mi.ado
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
*!plssem_mi version 0.1.1
*!Written 03Aug2023
*!Written by Sergio Venturini and Mehmet Mehmetoglu
*!The following code is distributed under GNU General Public License version 3 (GPL-3)
program plssem_mi
version 15.1
syntax [anything] [if] [in] [, * ]
if replay() {
if ("`e(cmd)'" != "mi estimate") {
error 301
}
if (_by()) {
error 190
}
// Extract all the options from 'cmdline'
local cmdline = `"`e(cmdline)'"'
local cmdlen = strlen(`"`cmdline'"')
local cmdcomma = strpos(`"`cmdline'"', ",")
local old_options = substr(`"`cmdline'"', `cmdcomma' + 1, `cmdlen' - `cmdcomma')
local old_options : list clean old_options
local hasstruct = strpos(`"`old_options'"', "str")
if (!`hasstruct') {
local nostructural "nostructural"
}
if (`"`options'"' != "") {
if (`"`options'"' == "midisplay") {
mi estimate
}
else {
Display_mi, `options' `nostructural'
}
}
else {
Display_mi, `old_options' `nostructural'
}
exit
}
if (_caller() < 8) {
local version : display "version " string(_caller()) ", missing :"
}
else {
local version : display "version " string(_caller()) " :"
}
`version' Estimate_mi `0' // version is not necessary
end
program Estimate_mi, eclass
version 15.1
syntax anything [if] [in], [ MIOptions(string) MIDisplay * ]
/* Options:
--------
mioptions(string) --> options to pass to mi estimate
midisplay --> options to show results of mi estimate
*/
local tempnamelist
/* Recover some plssem properties */
quietly plssem `anything', `options'
local props = e(properties)
local allindicators = e(mvs)
local modeA = e(reflective)
local binary `"`e(binarylvs)'"'
local init : word 1 of `props'
local wscheme : word 2 of `props'
/* End recovering plssem properties */
/* Recover the structural option */
local structural
local struct "structural"
local isstruct : list struct in props
if (!`isstruct') {
local structural "nostructural"
}
local num_ind: word count `allindicators'
local num_lv_A: word count `modeA'
/* End of recovering the structural option */
/* Recover the digits option */
local digits
gettoken part rest : options
while `"`part'"' != "" {
local lopt = length("`part'")
if (substr("`part'", 1, min(3, `lopt')) == "dig") {
tokenize `"`part'"', parse("()")
local digits = `3'
continue, break
}
gettoken part rest : rest
}
if ("`digits'" == "") {
local digits = 3
}
/* End of recovering the digits option */
/* Recover the boot option */
local bootstrap "bootstrap"
local isboot : list bootstrap in props
local boot
if (`isboot') {
local boot "bootstrap"
}
/* End of recovering the boot option */
/* Recover the rawsum option */
local rawsum
gettoken part rest : options
while `"`part'"' != "" {
local lopt = length("`part'")
if (substr("`part'", 1, min(3, `lopt')) == "raw") {
local rawsum = "rawsum"
continue, break
}
gettoken part rest : rest
}
/* End of recovering the rawsum option */
/* Recover the noheader option */
local header
gettoken part rest : options
while `"`part'"' != "" {
local lopt = length("`part'")
if (substr("`part'", 3, min(4, `lopt')) == "head") {
local header = "noheader"
continue, break
}
gettoken part rest : rest
}
/* End of recovering the noheader option */
/* Recover the nomeastable option */
local meastable
gettoken part rest : options
while `"`part'"' != "" {
local lopt = length("`part'")
if (substr("`part'", 3, min(4, `lopt')) == "meas") {
local meastable = "nomeastable"
continue, break
}
gettoken part rest : rest
}
/* End of recovering the nomeastable option */
/* Recover the nostructtable option */
local structtable
gettoken part rest : options
while `"`part'"' != "" {
local lopt = length("`part'")
if (substr("`part'", 3, min(6, `lopt')) == "struct") {
local structtable = "nostructtable"
continue, break
}
gettoken part rest : rest
}
/* End of recovering the nostructtable option */
/* Recover the loadpval option */
local loadpval
gettoken part rest : options
while `"`part'"' != "" {
local lopt = length("`part'")
if (substr("`part'", 1, min(5, `lopt')) == "loadp") {
local loadpval = "loadpval"
continue, break
}
gettoken part rest : rest
}
/* End of recovering the loadpval option */
if ("`midisplay'" == "") {
/* Multiple imputation analysis */
mi estimate, cmdok noheader notable `mioptions': plssem `anything', `options'
/* End of multiple imputation analysis */
/* Display results */
Display_mi, wscheme(`wscheme') init(`init') `structural' ///
digits(`digits') boot(`boot') `header' `meastable' `structtable' ///
`loadpval' binary(`binary') `rawsum'
/* End of displaying results */
}
else {
/* Multiple imputation analysis */
mi estimate, cmdok `mioptions': plssem `anything', `options'
/* End of multiple imputation analysis */
}
/* Clean up */
if ("`cleanup'" == "") {
capture mata: cleanup()
// capture mata: cleanup(st_local("tempnamelist"))
}
/* End of cleaning up */
end
program Display_mi
version 15.1
syntax [, WScheme(string) INit(string) noSTRuctural DIGits(integer 3) ///
Boot(string) noHEADer noMEAStable noSTRUCTtable LOADPval ///
BINary(namelist min=1) RAWsum * ]
if (`digits' < 0) {
display as error "number of digits to display must be a nonnegative integer"
exit
}
if ("`header'" == "") {
if ("`structural'" != "nostructural") {
mkheader_mi, wscheme(`wscheme') init(`init') digits(5)
}
else {
mkheader_mi, wscheme(`wscheme') init(`init') digits(5) nostructural
}
}
if ("`meastable'" == "") {
tempname adj_meas b_mi V_mi loadings
mata: `adj_meas' = st_matrix("e(adj_meas)")
mata: `b_mi' = st_matrix("e(b_mi)")
mata: `b_mi' = `b_mi'[1, 1..rows(`adj_meas')]
mata: st_matrix("`loadings'", editvalue(`adj_meas' :* `b_mi'', 0, .))
matrix rownames `loadings' = `: rownames e(adj_meas)'
matrix colnames `loadings' = `: colfullnames e(adj_meas)'
local num_lv = colsof(`loadings')
local allformative = e(formative)
local num_lv_B : word count `allformative'
local num_lv_A = `num_lv' - `num_lv_B'
local num_ind = rowsof(`loadings')
local title_meas "Measurement model - Standardized loadings"
mktable, matrix(`loadings') digits(`digits') firstcolname("") ///
title(`title_meas') firstcolwidth(14) colwidth(14) ///
hlines(`num_ind') novlines
if ("`loadpval'" != "") {
tempname SE_mi loadings_se nindblock loadings_df loadings_pval
mata: `SE_mi' = sqrt(diagonal(st_matrix("e(V_mi)")))'
mata: `SE_mi' = `SE_mi'[1, 1..rows(`adj_meas')]
mata: st_matrix("`loadings_se'", editvalue(`adj_meas' :* `SE_mi'', 0, .))
matrix rownames `loadings_se' = `: rownames e(adj_meas)'
matrix colnames `loadings_se' = `: colfullnames e(adj_meas)'
mata: st_matrix("`nindblock'", colsum(`adj_meas'))
mata: st_matrix("`loadings_df'", ///
`adj_meas'*(st_numscalar("e(N)") - 1))
local alllatents = e(lvs)
if (`num_lv_B' > 0) {
local indi = 1
local p = 1
foreach lv in `alllatents' {
local nbl = `nindblock'[1, `p']
forvalues k = 1/`nbl' {
if (`: list lv in allformative') {
matrix `loadings_df'[`indi', `p'] = `loadings_df'[`indi', `p'] - ///
`nindblock'[1, `p']
}
else {
matrix `loadings_df'[`indi', `p'] = `loadings_df'[`indi', `p'] - 1
}
local ++indi
}
local ++p
}
}
mata: st_matrix("`loadings_pval'", 2*ttail(st_matrix("`loadings_df'"), ///
abs(st_matrix("`loadings'") :/ st_matrix("`loadings_se'"))))
// mata: _editmissing(st_matrix("`loadings_pval'"), 0)
matrix rownames `loadings_pval' = `: rowfullnames `loadings''
matrix colnames `loadings_pval' = `: colfullnames `loadings''
if ("`boot'" == "") {
local title_meas "Measurement model - Standardized loading p-values"
}
else {
local title_meas "Measurement model - Standardized loading p-values (Bootstrap)"
}
mktable, matrix(`loadings_pval') digits(`digits') firstcolname("") ///
title(`title_meas') firstcolwidth(14) colwidth(14) ///
hlines(`num_ind') novlines
}
}
if ("`structural'" != "nostructural") {
if ("`structtable'" == "") {
tempname adj_meas adj_struct path_mi pathSE_mi path_pval_mi ///
pathtab endo exo
mata: `adj_meas' = st_matrix("e(adj_meas)")
mata: `adj_struct' = st_matrix("e(adj_struct)")
mata: `path_mi' = st_matrix("e(b_mi)")
mata: `path_mi' = ///
`path_mi'[1, (sum(`adj_meas') + 1)..(sum(`adj_meas') + sum(`adj_struct'))]'
mata: `path_mi' = plssem_vec_to_matrix(`path_mi', `adj_struct')
mata: `pathSE_mi' = sqrt(diagonal(st_matrix("e(V_mi)")))
mata: `pathSE_mi' = ///
`pathSE_mi'[(sum(`adj_meas') + 1)..(sum(`adj_meas') + sum(`adj_struct')), 1]
mata: `pathSE_mi' = plssem_vec_to_matrix(`pathSE_mi', `adj_struct')
local alllatents = e(lvs)
mata: `path_pval_mi' = ///
plssem_pval( ///
`path_mi', ///
`pathSE_mi', ///
"`alllatents'", ///
"`binary'", ///
st_numscalar("e(N_mi)"), ///
("`boot'" != ""))
mata: st_matrix("`pathtab'", plssem_pathtab(`path_mi', `path_pval_mi'))
mata: st_matrix("`endo'", colsum(`adj_struct') :> 0)
mata: st_matrix("`exo'", rowsum(`adj_struct') :> 0)
mata: st_local("num_lv", strofreal(cols(`adj_struct')))
local pathtab_rown ""
local idx = 1
foreach lv in `: rownames e(adj_struct)' {
if (`exo'[`idx', 1]) {
local pathtab_rown "`pathtab_rown' `lv' ."
}
local ++idx
}
local pathtab_coln ""
local idx = 1
foreach lv in `: colnames e(adj_struct)' {
if (`endo'[1, `idx']) {
local pathtab_coln "`pathtab_coln' `lv'"
}
local ++idx
}
matrix rownames `pathtab' = `pathtab_rown'
matrix colnames `pathtab' = `pathtab_coln'
local hline_path = rowsof(`pathtab')
if ("`boot'" == "") {
local title_st "Structural model - Standardized path coefficients"
}
else {
local title_st "Structural model - Standardized path coefficients (Bootstrap)"
}
mktable, matrix(`pathtab') digits(`digits') firstcolname("Variable") ///
title(`title_st') firstcolwidth(14) colwidth(14) ///
hlines(`hline_path') novlines path binary(`binary')
}
}
end