-
Notifications
You must be signed in to change notification settings - Fork 0
/
01_Basic.html
1203 lines (1165 loc) · 93.1 KB
/
01_Basic.html
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
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head>
<meta charset="utf-8">
<meta name="generator" content="quarto-1.4.555">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<meta name="author" content="Piotr Koc">
<meta name="author" content="Julian Urban">
<meta name="author" content="David Grüning">
<title>Basic Analysis for Scale Archiving</title>
<style>
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
div.columns{display: flex; gap: min(4vw, 1.5em);}
div.column{flex: auto; overflow-x: auto;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
ul.task-list{list-style: none;}
ul.task-list li input[type="checkbox"] {
width: 0.8em;
margin: 0 0.8em 0.2em -1em; /* quarto-specific, see https://github.com/quarto-dev/quarto-cli/issues/4556 */
vertical-align: middle;
}
/* CSS for syntax highlighting */
pre > code.sourceCode { white-space: pre; position: relative; }
pre > code.sourceCode > span { line-height: 1.25; }
pre > code.sourceCode > span:empty { height: 1.2em; }
.sourceCode { overflow: visible; }
code.sourceCode > span { color: inherit; text-decoration: inherit; }
div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
pre > code.sourceCode { white-space: pre-wrap; }
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
}
pre.numberSource code
{ counter-reset: source-line 0; }
pre.numberSource code > span
{ position: relative; left: -4em; counter-increment: source-line; }
pre.numberSource code > span > a:first-child::before
{ content: counter(source-line);
position: relative; left: -1em; text-align: right; vertical-align: baseline;
border: none; display: inline-block;
-webkit-touch-callout: none; -webkit-user-select: none;
-khtml-user-select: none; -moz-user-select: none;
-ms-user-select: none; user-select: none;
padding: 0 4px; width: 4em;
}
pre.numberSource { margin-left: 3em; padding-left: 4px; }
div.sourceCode
{ }
@media screen {
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
}
/* CSS for citations */
div.csl-bib-body { }
div.csl-entry {
clear: both;
margin-bottom: 0em;
}
.hanging-indent div.csl-entry {
margin-left:2em;
text-indent:-2em;
}
div.csl-left-margin {
min-width:2em;
float:left;
}
div.csl-right-inline {
margin-left:2em;
padding-left:1em;
}
div.csl-indent {
margin-left: 2em;
}</style>
<script src="01_Basic_files/libs/clipboard/clipboard.min.js"></script>
<script src="01_Basic_files/libs/quarto-html/quarto.js"></script>
<script src="01_Basic_files/libs/quarto-html/popper.min.js"></script>
<script src="01_Basic_files/libs/quarto-html/tippy.umd.min.js"></script>
<script src="01_Basic_files/libs/quarto-html/anchor.min.js"></script>
<link href="01_Basic_files/libs/quarto-html/tippy.css" rel="stylesheet">
<link href="01_Basic_files/libs/quarto-html/quarto-syntax-highlighting.css" rel="stylesheet" id="quarto-text-highlighting-styles">
<script src="01_Basic_files/libs/bootstrap/bootstrap.min.js"></script>
<link href="01_Basic_files/libs/bootstrap/bootstrap-icons.css" rel="stylesheet">
<link href="01_Basic_files/libs/bootstrap/bootstrap.min.css" rel="stylesheet" id="quarto-bootstrap" data-mode="light">
<link rel="stylesheet" href="technical/styles.css">
</head>
<body>
<div id="quarto-content" class="page-columns page-rows-contents page-layout-article toc-left">
<div id="quarto-sidebar-toc-left" class="sidebar toc-left">
<nav id="TOC" role="doc-toc" class="toc-active">
<h2 id="toc-title">Table of contents</h2>
<ul>
<li><a href="#introduction" id="toc-introduction" class="nav-link active" data-scroll-target="#introduction">Introduction</a></li>
<li><a href="#data-preparation-descriptive-analysis" id="toc-data-preparation-descriptive-analysis" class="nav-link" data-scroll-target="#data-preparation-descriptive-analysis">Data Preparation & Descriptive Analysis</a></li>
<li><a href="#dimensionality-assessment-factorial-validity" id="toc-dimensionality-assessment-factorial-validity" class="nav-link" data-scroll-target="#dimensionality-assessment-factorial-validity">Dimensionality Assessment & Factorial Validity</a>
<ul class="collapse">
<li><a href="#exploratory-factor-analysis" id="toc-exploratory-factor-analysis" class="nav-link" data-scroll-target="#exploratory-factor-analysis">Exploratory Factor Analysis</a></li>
<li><a href="#confirmatory-factor-analysis-cfa" id="toc-confirmatory-factor-analysis-cfa" class="nav-link" data-scroll-target="#confirmatory-factor-analysis-cfa">Confirmatory Factor Analysis (CFA)</a></li>
</ul></li>
<li><a href="#descriptive-statistics-of-indicators-reliability-and-criterion-validity" id="toc-descriptive-statistics-of-indicators-reliability-and-criterion-validity" class="nav-link" data-scroll-target="#descriptive-statistics-of-indicators-reliability-and-criterion-validity">Descriptive statistics of indicators, reliability, and criterion validity</a></li>
<li><a href="#descriptive-statistics-of-the-scales" id="toc-descriptive-statistics-of-the-scales" class="nav-link" data-scroll-target="#descriptive-statistics-of-the-scales">Descriptive statistics of the scales</a></li>
</ul>
</nav>
</div>
<div id="quarto-margin-sidebar" class="sidebar margin-sidebar">
</div>
<main class="content page-columns page-full" id="quarto-document-content">
<header id="title-block-header" class="quarto-title-block default">
<div class="quarto-title">
<div class="title-container">
<h1 class="title">Basic Analysis for Scale Archiving</h1>
<p class="subtitle lead"><em><em>ZIS R-Tutorials</em></em></p>
</div>
<div class="logo">
<img src="pics/zis_logo.svg" height="80">
</div>
</div>
<div class="quarto-title-meta-author">
<div class="quarto-title-meta-heading">Authors</div>
<div class="quarto-title-meta-heading">Affiliations</div>
<div class="quarto-title-meta-contents">
<p class="author">Piotr Koc </p>
</div>
<div class="quarto-title-meta-contents">
<p class="affiliation">
GESIS – Leibniz Institute for the Social Sciences
</p>
</div>
<div class="quarto-title-meta-contents">
<p class="author">Julian Urban </p>
</div>
<div class="quarto-title-meta-contents">
<p class="affiliation">
GESIS – Leibniz Institute for the Social Sciences
</p>
</div>
<div class="quarto-title-meta-contents">
<p class="author">David Grüning </p>
</div>
<div class="quarto-title-meta-contents">
<p class="affiliation">
Heidelberg University; GESIS – Leibniz Institute for the Social Sciences
</p>
</div>
</div>
<div class="quarto-title-meta">
<div>
<div class="quarto-title-meta-heading">Published</div>
<div class="quarto-title-meta-contents">
<p class="date">01.07.2024</p>
</div>
</div>
<div>
<div class="quarto-title-meta-heading">Modified</div>
<div class="quarto-title-meta-contents">
<p class="date">15.08.2024</p>
</div>
</div>
</div>
</header>
<section id="introduction" class="level2">
<h2 class="anchored" data-anchor-id="introduction">Introduction</h2>
<p>The following tutorial presents the basic analysis required for an instrument to be archived in the Open Access Repository for Measurement Instruments (ZIS). As an example, we use a scale with continuous indicators, so not all parts of the analysis are appropriate for instruments with categorical indicators. We point this out whenever relevant. The treatment of categorical indicators is covered in a separate tutorial.</p>
</section>
<section id="data-preparation-descriptive-analysis" class="level2">
<h2 class="anchored" data-anchor-id="data-preparation-descriptive-analysis">Data Preparation & Descriptive Analysis</h2>
<p>In this tutorial, we will use the <code>HolzingerSwineford1939</code> data set, which contains mental ability test scores of seventh- and eighth-grade children from two different schools (Pasteur and Grant-White).</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb1"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="fu">library</span>(lavaan)</span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="fu">library</span>(semTools)</span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="fu">library</span>(psych)</span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="fu">library</span>(Hmisc)</span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a><span class="fu">library</span>(dplyr)</span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a><span class="co"># Loading the data</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a>Data <span class="ot"><-</span> lavaan<span class="sc">::</span>HolzingerSwineford1939</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
</div>
<p>First, let’s compute the descriptives for the nominal variables — the counts. We can compute the counts using the <code>table()</code> function.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb2"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="co"># Count for a single variable</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="fu">table</span>(Data<span class="sc">$</span>sex,</span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a> <span class="at">useNA =</span> <span class="st">"always"</span>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>
1 2 <NA>
146 155 0 </code></pre>
</div>
</div>
<p>If we have multiple variables, we can use a loop that iterates over the elements of the <code>nominal_variables</code> vector and produces as many tables with counts as there are variables in that vector.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb4"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="co"># Define nominal variables</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>nominal_variables <span class="ot"><-</span> <span class="fu">c</span>(<span class="st">"sex"</span>, <span class="st">"school"</span>, <span class="st">"grade"</span>)</span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="co"># Count for multiple variables</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>nominal_sample_statistics <span class="ot"><-</span> <span class="fu">list</span>()</span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span> (variable <span class="cf">in</span> nominal_variables) {</span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a> frequency_table <span class="ot"><-</span> <span class="fu">table</span>(Data[, variable],</span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a> <span class="at">useNA =</span> <span class="st">"always"</span>)</span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a> nominal_sample_statistics[[variable]] <span class="ot"><-</span> frequency_table</span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a>}</span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a>nominal_sample_statistics</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>$sex
1 2 <NA>
146 155 0
$school
Grant-White Pasteur <NA>
145 156 0
$grade
7 8 <NA>
157 143 1 </code></pre>
</div>
</div>
<p>For continuous variables, we compute the mean, standard deviation, skewness, excess kurtosis, and the percentage of missing data using the base R functions and <code>skew()</code> and <code>kurtosi()</code> functions from the <code>psych</code> package.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb6"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="co"># Compute aggregated age variable of year and months</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>Data<span class="sc">$</span>age <span class="ot"><-</span> (Data<span class="sc">$</span>ageyr <span class="sc">*</span> <span class="dv">12</span> <span class="sc">+</span> Data<span class="sc">$</span>agemo) <span class="sc">/</span> <span class="dv">12</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a><span class="co"># Estimate mean, sd, skew, kurtosis, and percentage missing</span></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a>avrg_ <span class="ot"><-</span> <span class="fu">mean</span>(Data<span class="sc">$</span>age, <span class="at">na.rm =</span> <span class="cn">TRUE</span>)</span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a>sd_ <span class="ot"><-</span> <span class="fu">sd</span>(Data<span class="sc">$</span>age, <span class="at">na.rm =</span> <span class="cn">TRUE</span>)</span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a>skw_ <span class="ot"><-</span>psych<span class="sc">::</span><span class="fu">skew</span>(Data<span class="sc">$</span>age, <span class="at">na.rm =</span> <span class="cn">TRUE</span>)</span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a>krtss_<span class="ot"><-</span> psych<span class="sc">::</span><span class="fu">kurtosi</span>(Data<span class="sc">$</span>age, <span class="at">na.rm =</span> <span class="cn">TRUE</span>)</span>
<span id="cb6-9"><a href="#cb6-9" aria-hidden="true" tabindex="-1"></a>mis_ <span class="ot"><-</span> <span class="fu">sum</span>(<span class="fu">is.na</span>(Data<span class="sc">$</span>age)) <span class="sc">/</span> <span class="fu">nrow</span>(Data)</span>
<span id="cb6-10"><a href="#cb6-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-11"><a href="#cb6-11" aria-hidden="true" tabindex="-1"></a>smmry <span class="ot"><-</span> <span class="fu">data.frame</span>(</span>
<span id="cb6-12"><a href="#cb6-12" aria-hidden="true" tabindex="-1"></a> <span class="at">var =</span> <span class="st">"age"</span>,</span>
<span id="cb6-13"><a href="#cb6-13" aria-hidden="true" tabindex="-1"></a> <span class="at">avrg_ =</span> avrg_,</span>
<span id="cb6-14"><a href="#cb6-14" aria-hidden="true" tabindex="-1"></a> <span class="at">sd_ =</span> sd_,</span>
<span id="cb6-15"><a href="#cb6-15" aria-hidden="true" tabindex="-1"></a> <span class="at">skw_ =</span> skw_,</span>
<span id="cb6-16"><a href="#cb6-16" aria-hidden="true" tabindex="-1"></a> <span class="at">krtss_ =</span> krtss_,</span>
<span id="cb6-17"><a href="#cb6-17" aria-hidden="true" tabindex="-1"></a> <span class="at">mis_ =</span> mis_</span>
<span id="cb6-18"><a href="#cb6-18" aria-hidden="true" tabindex="-1"></a>)</span>
<span id="cb6-19"><a href="#cb6-19" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-20"><a href="#cb6-20" aria-hidden="true" tabindex="-1"></a><span class="co"># Format the numeric columns to 2 decimal places using sprintf</span></span>
<span id="cb6-21"><a href="#cb6-21" aria-hidden="true" tabindex="-1"></a>smmry <span class="ot"><-</span> smmry <span class="sc">|></span></span>
<span id="cb6-22"><a href="#cb6-22" aria-hidden="true" tabindex="-1"></a> dplyr<span class="sc">::</span><span class="fu">mutate</span>(<span class="fu">across</span>(<span class="fu">c</span>(avrg_, sd_, skw_, krtss_), </span>
<span id="cb6-23"><a href="#cb6-23" aria-hidden="true" tabindex="-1"></a> <span class="sc">~</span> <span class="fu">sprintf</span>(<span class="st">"%.2f"</span>, .)))</span>
<span id="cb6-24"><a href="#cb6-24" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-25"><a href="#cb6-25" aria-hidden="true" tabindex="-1"></a><span class="co"># Rename columns</span></span>
<span id="cb6-26"><a href="#cb6-26" aria-hidden="true" tabindex="-1"></a><span class="fu">colnames</span>(smmry) <span class="ot"><-</span> <span class="fu">c</span>(<span class="st">"Variable"</span>, <span class="st">"Mean"</span>, <span class="st">"Standard Deviation"</span>, <span class="st">"Skewness"</span>, <span class="st">"Kurtosis"</span>, <span class="st">"% Missing Data"</span>)</span>
<span id="cb6-27"><a href="#cb6-27" aria-hidden="true" tabindex="-1"></a>smmry</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code> Variable Mean Standard Deviation Skewness Kurtosis % Missing Data
1 age 13.44 1.02 0.70 0.10 0</code></pre>
</div>
</div>
<p>Alternatively, we could use the <code>describe()</code> function from the <code>psych</code> package, which can be particularly useful with multiple continuous variables. The only caveat of that function is that it will not produce the percentage of missing observations per variable automatically, which we could easily circumvent by running <code>colSums(is.na(data))/nrow(data)</code>, where <code>colSums(is.na(data))</code> counts the occurrences of missing data for the variables in our data set, and <code>nrow(data)</code> gives us the total number of rows.</p>
</section>
<section id="dimensionality-assessment-factorial-validity" class="level2 page-columns page-full">
<h2 class="anchored" data-anchor-id="dimensionality-assessment-factorial-validity">Dimensionality Assessment & Factorial Validity</h2>
<p>First, we build a look-up table where items are assigned to different subscales. We will use the table for the subsequent analyses in this document.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb8"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="co"># Build lookup table for required items</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a>lookup_table <span class="ot"><-</span> <span class="fu">data.frame</span>(<span class="at">item =</span> <span class="fu">paste</span>(<span class="st">"x"</span>, <span class="fu">c</span>(<span class="dv">1</span><span class="sc">:</span><span class="dv">9</span>), <span class="at">sep =</span> <span class="st">""</span>),</span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a> <span class="at">subscale =</span> <span class="fu">c</span>(<span class="fu">rep</span>(<span class="fu">c</span>(<span class="st">"visual"</span>, <span class="st">"textual"</span>, <span class="st">"speed"</span>),</span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a> <span class="at">each =</span> <span class="dv">3</span>))</span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a> )</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
</div>
<section id="exploratory-factor-analysis" class="level3 page-columns page-full">
<h3 class="anchored" data-anchor-id="exploratory-factor-analysis">Exploratory Factor Analysis</h3>
<p>To decide how many latent dimension to extract, we will first use parallel analysis (for the factor solution, not principle components) and exploratory factor analysis. We run parallel analysis using the following syntax:</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb9"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="fu">set.seed</span>(<span class="dv">8576456</span>)</span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a><span class="co"># Conduct parallel analysis display screeplot</span></span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a>parallel_analyses_efa <span class="ot"><-</span> psych<span class="sc">::</span><span class="fu">fa.parallel</span>(Data[ , <span class="fu">unlist</span>(lookup_table<span class="sc">$</span>item)],</span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a> <span class="at">fa =</span> <span class="st">"fa"</span>, <span class="co"># Method to explore dimensionality: efa</span></span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a> <span class="at">fm =</span> <span class="st">"minres"</span>, <span class="at">nfactors =</span> <span class="dv">1</span>, <span class="at">SMC =</span> F,</span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a> <span class="at">n.iter =</span> <span class="dv">30</span>, <span class="co"># quant = .95,</span></span>
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a> <span class="at">cor =</span> <span class="st">"cor"</span>) </span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>Parallel analysis suggests that the number of factors = 3 and the number of components = NA </code></pre>
</div>
<div class="cell-output-display">
<div id="fig-figpar" class="quarto-figure quarto-figure-center quarto-float anchored" width="672">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-figpar-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="01_Basic_files/figure-html/fig-figpar-1.png" id="fig-figpar" class="img-fluid figure-img" width="672">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig quarto-uncaptioned" id="fig-figpar-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure 1
</figcaption>
</figure>
</div>
</div>
</div>
<div class="no-row-height column-margin column-container"><div class="">
<p>For categorical data, we would need to change the <code>cor =</code> argument in the <code>fa.parallel()</code> function to <code>"poly"</code> and use polychoric correlations.</p>
</div></div><p>The idea behind parallel analysis in exploratory factor analysis (EFA) involves comparing the eigenvalues from our actual data to those from randomly generated data to determine the number of factors to retain. The random datasets match our actual dataset in terms of sample size and the number of variables. Eigenvalues are calculated for both the real data and the random data. This process is repeated multiple times to generate a distribution of eigenvalues for the random data.</p>
<p>The key step is then to compare the eigenvalues from our actual data with the mean (or sometimes the 95th percentile) of the eigenvalues from the random datasets. We retain those factors where the actual eigenvalue exceeds the corresponding eigenvalue from the random data. In our case, <a href="#fig-figpar" class="quarto-xref">Figure 1</a> with a scree plot suggests that we should extract three factors.</p>
<div class="callout callout-style-simple callout-important callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Be careful
</div>
</div>
<div class="callout-body-container callout-body">
<p>Quite often, researchers use the Kaiser-1 rule to decide on the number of latent factors to extract. That is, they check how many eigenvalues are greater than 1. This method has been shown to not be robust and can result in extracting too many latent dimensions <span class="citation" data-cites="russell_search_2002 van_der_eijk_risky_2015">(see, <a href="#ref-russell_search_2002" role="doc-biblioref">Russell 2002</a>; <a href="#ref-van_der_eijk_risky_2015" role="doc-biblioref">Van Der Eijk and Rose 2015</a>)</span>. Hence, you should probably refrain from using it.</p>
</div>
</div>
<p>Knowing how many factors to extract, we will estimate now an EFA model with three factors using the oblique rotation and minimal residuals (a.k.a. ordinary least squares) as the extraction method<a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a>.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb11"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="co"># Estimate exploratory factor analyses</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a>efa <span class="ot"><-</span> psych<span class="sc">::</span><span class="fu">fa</span>(Data[ , <span class="fu">unlist</span>(lookup_table<span class="sc">$</span>item)],</span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a> <span class="at">fm =</span> <span class="st">"pa"</span>,</span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a> <span class="at">nfactors =</span> <span class="dv">3</span>,</span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a> <span class="at">rotate =</span> <span class="st">"oblimin"</span>,</span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a> <span class="at">scores =</span> <span class="st">"regression"</span>, <span class="at">oblique.scores =</span> <span class="cn">FALSE</span>,</span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a> <span class="at">SMC =</span> <span class="cn">TRUE</span>,</span>
<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a> <span class="at">cor =</span> <span class="st">"cor"</span>)</span>
<span id="cb11-9"><a href="#cb11-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-10"><a href="#cb11-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-11"><a href="#cb11-11" aria-hidden="true" tabindex="-1"></a><span class="co"># matrix of factor loadings</span></span>
<span id="cb11-12"><a href="#cb11-12" aria-hidden="true" tabindex="-1"></a><span class="fu">round</span>(efa[[<span class="st">"loadings"</span>]], <span class="at">digits =</span> <span class="dv">2</span>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>
Loadings:
PA1 PA3 PA2
x1 0.20 0.59
x2 0.51 -0.12
x3 0.69
x4 0.85
x5 0.89
x6 0.81
x7 -0.15 0.73
x8 0.12 0.69
x9 0.38 0.46
PA1 PA3 PA2
SS loadings 2.219 1.276 1.237
Proportion Var 0.247 0.142 0.137
Cumulative Var 0.247 0.388 0.526</code></pre>
</div>
</div>
<p>The output of the <code>fa()</code> function is very detailed and potentially overwhelming, so we are not showing it in its entirety. Instead we focus on the matrix of factor loadings.</p>
<p>By looking at the matrix, we can see that items <code>x1-x3</code> have high loadings on the factor <code>PA3</code>, items <code>x4-x6</code> on the factor <code>PA1</code>, and items <code>x7-x9</code> on <code>PA2</code>. We will use this insight to specify our confirmatory model.</p>
</section>
<section id="confirmatory-factor-analysis-cfa" class="level3 page-columns page-full">
<h3 class="anchored" data-anchor-id="confirmatory-factor-analysis-cfa">Confirmatory Factor Analysis (CFA)</h3>
<p>To estimate the confirmatory factor analytic model, we will use the <code>lavaan</code> package. We specify three models:</p>
<ol type="1">
<li>Unidimensional model (one-factor model);</li>
<li>Three-dimensional congeneric model;</li>
<li>Three-dimensional tau-equivalent model.</li>
</ol>
<p>While it often makes sense to compare models 1 and 2 because model 1 is typically considered more parsimonious (having fewer latent factors), it might not be clear why we would estimate models 2 and 3, and what the terms “congeneric” and “tau-equivalent” even mean.</p>
<p>In the congeneric model, we assume that the indicators measure the same construct but not necessarily to the same degree. With the tau-equivalent model, we assume that the indicators measure the construct to the same degree, and we enforce this by constraining the unstandardized factor loadings of each factor to equality. If the fit of the latter is not substantially worse than the former, we can conclude that the indicators are tau-equivalent <span class="citation" data-cites="kline_principles_2016">(<a href="#ref-kline_principles_2016" role="doc-biblioref">Kline 2016</a>)</span>.</p>
<p>One of the significant advantages of the tau-equivalent model is that it allows for greater comparability of scores across independent studies using the same items, as the scores do not depend on study-specific factor loadings <span class="citation" data-cites="widaman_thinking_2023">(<a href="#ref-widaman_thinking_2023" role="doc-biblioref">Widaman and Revelle 2023</a>)</span>.</p>
<p>To estimate the three models, we first define the model syntax. Then we specify the estimator as Robust Maximum Likelihood (MLR) and set the option <code>std.lv = TRUE</code> to impose the identification constraints on the model, i.e., the mean of the latent variable is equal to 0 and the variance is equal to 1<a href="#fn2" class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a>. We use MLR by default as it also works in situations where continuous indicators have severely non-normal distributions.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb13"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="co"># Define models</span></span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a>one_factor_model <span class="ot"><-</span> <span class="st">'</span></span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a><span class="st">g_factor =~ x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9</span></span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a><span class="st">'</span></span>
<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a>three_factor_model <span class="ot"><-</span> <span class="st">'</span></span>
<span id="cb13-7"><a href="#cb13-7" aria-hidden="true" tabindex="-1"></a><span class="st">visual =~ x1 + x2 + x3</span></span>
<span id="cb13-8"><a href="#cb13-8" aria-hidden="true" tabindex="-1"></a><span class="st">textual =~ x4 + x5 + x6</span></span>
<span id="cb13-9"><a href="#cb13-9" aria-hidden="true" tabindex="-1"></a><span class="st">speed =~ x7 + x8 + x9</span></span>
<span id="cb13-10"><a href="#cb13-10" aria-hidden="true" tabindex="-1"></a><span class="st">'</span></span>
<span id="cb13-11"><a href="#cb13-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-12"><a href="#cb13-12" aria-hidden="true" tabindex="-1"></a>three_factor_tau_model <span class="ot"><-</span> <span class="st">'</span></span>
<span id="cb13-13"><a href="#cb13-13" aria-hidden="true" tabindex="-1"></a><span class="st">visual =~ a*x1 + a*x2 + a*x3</span></span>
<span id="cb13-14"><a href="#cb13-14" aria-hidden="true" tabindex="-1"></a><span class="st">textual =~ b*x4 + b*x5 + b*x6</span></span>
<span id="cb13-15"><a href="#cb13-15" aria-hidden="true" tabindex="-1"></a><span class="st">speed =~ c*x7 + c*x8 + c*x9</span></span>
<span id="cb13-16"><a href="#cb13-16" aria-hidden="true" tabindex="-1"></a><span class="st">'</span></span>
<span id="cb13-17"><a href="#cb13-17" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-18"><a href="#cb13-18" aria-hidden="true" tabindex="-1"></a><span class="co"># Estimate cfa</span></span>
<span id="cb13-19"><a href="#cb13-19" aria-hidden="true" tabindex="-1"></a><span class="co"># One factor model</span></span>
<span id="cb13-20"><a href="#cb13-20" aria-hidden="true" tabindex="-1"></a>one_factor_cfa <span class="ot"><-</span> lavaan<span class="sc">::</span><span class="fu">cfa</span>(<span class="at">model =</span> one_factor_model,</span>
<span id="cb13-21"><a href="#cb13-21" aria-hidden="true" tabindex="-1"></a> <span class="at">data =</span> Data,</span>
<span id="cb13-22"><a href="#cb13-22" aria-hidden="true" tabindex="-1"></a> <span class="at">estimator =</span> <span class="st">'mlr'</span>,</span>
<span id="cb13-23"><a href="#cb13-23" aria-hidden="true" tabindex="-1"></a> <span class="at">std.lv =</span> <span class="cn">TRUE</span>)</span>
<span id="cb13-24"><a href="#cb13-24" aria-hidden="true" tabindex="-1"></a><span class="co"># Three factor model</span></span>
<span id="cb13-25"><a href="#cb13-25" aria-hidden="true" tabindex="-1"></a>three_factor_cfa <span class="ot"><-</span> lavaan<span class="sc">::</span><span class="fu">cfa</span>(<span class="at">model =</span> three_factor_model,</span>
<span id="cb13-26"><a href="#cb13-26" aria-hidden="true" tabindex="-1"></a> <span class="at">data =</span> Data,</span>
<span id="cb13-27"><a href="#cb13-27" aria-hidden="true" tabindex="-1"></a> <span class="at">estimator =</span> <span class="st">'mlr'</span>,</span>
<span id="cb13-28"><a href="#cb13-28" aria-hidden="true" tabindex="-1"></a> <span class="at">std.lv =</span> <span class="cn">TRUE</span>)</span>
<span id="cb13-29"><a href="#cb13-29" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-30"><a href="#cb13-30" aria-hidden="true" tabindex="-1"></a><span class="co"># Three factor model model with essential tau equivalence</span></span>
<span id="cb13-31"><a href="#cb13-31" aria-hidden="true" tabindex="-1"></a>three_factor_tau_cfa <span class="ot"><-</span> lavaan<span class="sc">::</span><span class="fu">cfa</span>(<span class="at">model =</span> three_factor_tau_model,</span>
<span id="cb13-32"><a href="#cb13-32" aria-hidden="true" tabindex="-1"></a> <span class="at">data =</span> Data,</span>
<span id="cb13-33"><a href="#cb13-33" aria-hidden="true" tabindex="-1"></a> <span class="at">estimator =</span> <span class="st">'mlr'</span>,</span>
<span id="cb13-34"><a href="#cb13-34" aria-hidden="true" tabindex="-1"></a> <span class="at">std.lv =</span> <span class="cn">TRUE</span>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
</div>
<div class="no-row-height column-margin column-container"><div class="">
<p>For categorical data, we would change the <code>cfa()</code> call and specify which variables should be treated as categorical by using the <code>ordered</code> argument. <code>lavaan</code> would then automatically switch to an appropriate estimator — diagonally weighted least squares.</p>
</div></div><p>Once the models are estimated and no warning messages are shown, we can inspect the global fit of the models.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb14"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="co"># model fit</span></span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a><span class="co"># Define fit measures of interest</span></span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a><span class="co"># use robust versions</span></span>
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a>fit_measures <span class="ot"><-</span> <span class="fu">c</span>(<span class="st">"chisq.scaled"</span>, <span class="st">"df"</span>, <span class="st">"pvalue.scaled"</span>,</span>
<span id="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a> <span class="st">"cfi.robust"</span>, <span class="st">"rmsea.robust"</span>, <span class="st">"srmr"</span>,</span>
<span id="cb14-6"><a href="#cb14-6" aria-hidden="true" tabindex="-1"></a> <span class="st">"aic"</span>, <span class="st">"bic"</span>, <span class="st">"bic2"</span>)</span>
<span id="cb14-7"><a href="#cb14-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb14-8"><a href="#cb14-8" aria-hidden="true" tabindex="-1"></a><span class="co"># Extract model fit</span></span>
<span id="cb14-9"><a href="#cb14-9" aria-hidden="true" tabindex="-1"></a><span class="fu">round</span>(lavaan<span class="sc">::</span><span class="fu">fitMeasures</span>(one_factor_cfa, <span class="at">fit.measures =</span> fit_measures), <span class="at">digits =</span> <span class="dv">3</span>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code> chisq.scaled df pvalue.scaled cfi.robust rmsea.robust
315.833 27.000 0.000 0.676 0.187
srmr aic bic bic2
0.143 7738.448 7805.176 7748.091 </code></pre>
</div>
<div class="sourceCode cell-code" id="cb16"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a><span class="fu">round</span>(lavaan<span class="sc">::</span><span class="fu">fitMeasures</span>(three_factor_cfa, <span class="at">fit.measures =</span> fit_measures), <span class="at">digits =</span> <span class="dv">3</span>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code> chisq.scaled df pvalue.scaled cfi.robust rmsea.robust
87.132 24.000 0.000 0.930 0.092
srmr aic bic bic2
0.065 7517.490 7595.339 7528.739 </code></pre>
</div>
<div class="sourceCode cell-code" id="cb18"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a><span class="fu">round</span>(lavaan<span class="sc">::</span><span class="fu">fitMeasures</span>(three_factor_tau_cfa, <span class="at">fit.measures =</span> fit_measures), <span class="at">digits =</span> <span class="dv">3</span>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code> chisq.scaled df pvalue.scaled cfi.robust rmsea.robust
103.426 30.000 0.000 0.913 0.092
srmr aic bic bic2
0.084 7527.595 7583.202 7535.630 </code></pre>
</div>
</div>
<p>First, we inspect the scaled chi-square and the corresponding p-values. They suggest that our models fail the exact-fit test and do not fit the data well.</p>
<p>We also check the most common approximate fit indices, i.e., the robust versions of the Comparative Fit Index (CFI), the Root Mean Square Error of Approximation (RMSEA), and the Standardized Root Mean Square Residual (SRMR)<a href="#fn3" class="footnote-ref" id="fnref3" role="doc-noteref"><sup>3</sup></a>. Different cut-off values are proposed in the literature for these indices <span class="citation" data-cites="hu_cutoff_1999 byrne_structural_1994">(e.g., <a href="#ref-hu_cutoff_1999" role="doc-biblioref">Hu and Bentler 1999</a>; <a href="#ref-byrne_structural_1994" role="doc-biblioref">Byrne 1994</a>)</span>. We will assume that CFI values smaller than .950, RMSEA values greater than .08, and SRMR values greater than .10 suggest a poor fit. In the case of all our models, the indices suggest an unsatisfactory fit, with the three-factor model with varying loadings being the best-fitting.</p>
<div class="callout callout-style-simple callout-important callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Be careful
</div>
</div>
<div class="callout-body-container callout-body">
<p>Even though in this tutorial we follow the common practice of using fixed cut-off values for evaluating model fit, this approach is not recommended by current literature. The universally used cut-off values are based on simulation studies with a limited set of conditions, which can substantially deviate from the ones researchers face <span class="citation" data-cites="groskurth_why_2023 mcneish_dynamic_2023">(see, <a href="#ref-groskurth_why_2023" role="doc-biblioref">Groskurth, Bluemke, and Lechner 2023</a>; <a href="#ref-mcneish_dynamic_2023" role="doc-biblioref">McNeish and Wolf 2023</a>)</span>. Ideally, researchers should derive the cut-offs using simulation-based techniques. This can be done using, for example, the Shiny app developed by <span class="citation" data-cites="mcneish_dynamic_2023">McNeish and Wolf (<a href="#ref-mcneish_dynamic_2023" role="doc-biblioref">2023</a>)</span> - https://dynamicfit.app/connect/.</p>
</div>
</div>
<p>We can use a statistical test to compare these models, specifically the scaled chi-squared difference test. We exclude the one-factor model from the comparison since its fit is much worse than either of the three-dimensional models. To conduct the test, we use the <code>anova()</code> function.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb20"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a><span class="fu">anova</span>(three_factor_cfa, three_factor_tau_cfa)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>
Scaled Chi-Squared Difference Test (method = "satorra.bentler.2001")
lavaan NOTE:
The "Chisq" column contains standard test statistics, not the
robust test that should be reported per model. A robust difference
test is a function of two standard (not robust) statistics.
Df AIC BIC Chisq Chisq diff Df diff Pr(>Chisq)
three_factor_cfa 24 7517.5 7595.3 85.305
three_factor_tau_cfa 30 7527.6 7583.2 107.411 17.317 6 0.008185 **
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1</code></pre>
</div>
</div>
<p>The test confirms the conclusions from the comparison of fit indices — the model with varying factor loadings fits the data best.</p>
<p>To identify the problems with the best-fitting model, we will evaluate the local model fit. Specifically, we will inspect the matrix of correlation residuals and look for the residuals whose absolute value is greater than .10, as they can be suggestive of model misfit.<a href="#fn4" class="footnote-ref" id="fnref4" role="doc-noteref"><sup>4</sup></a></p>
<div class="cell">
<div class="sourceCode cell-code" id="cb22"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb22-1"><a href="#cb22-1" aria-hidden="true" tabindex="-1"></a><span class="co"># Evaluate local model fit</span></span>
<span id="cb22-2"><a href="#cb22-2" aria-hidden="true" tabindex="-1"></a><span class="co"># Extract residual correlaton matrix</span></span>
<span id="cb22-3"><a href="#cb22-3" aria-hidden="true" tabindex="-1"></a>lavaan<span class="sc">::</span><span class="fu">lavResiduals</span>(three_factor_cfa)<span class="sc">$</span>cov</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code> x1 x2 x3 x4 x5 x6 x7 x8 x9
x1 0.000
x2 -0.030 0.000
x3 -0.008 0.094 0.000
x4 0.071 -0.012 -0.068 0.000
x5 -0.009 -0.027 -0.151 0.005 0.000
x6 0.060 0.030 -0.026 -0.009 0.003 0.000
x7 -0.140 -0.189 -0.084 0.037 -0.036 -0.014 0.000
x8 -0.039 -0.052 -0.012 -0.067 -0.036 -0.022 0.075 0.000
x9 0.149 0.073 0.147 0.048 0.067 0.056 -0.038 -0.032 0.000</code></pre>
</div>
</div>
<p>The inspection of the residuals reveals that there are five residuals greater than .10, which suggests the violation of the conditional independence assumption between those pairs of indicators:</p>
<ul>
<li><code>x1</code> with <code>x7</code> and <code>x9</code>;</li>
<li><code>x2</code> with <code>x7</code>;</li>
<li><code>x3</code> with <code>x5</code> and <code>x9</code>.</li>
</ul>
<p>In a real-world application, we would know more about the items than just the few keywords provided in the <code>HolzingerSwineford1939</code> dataset. In any case, we see that our model generally fails to account for the observed correlations between the items belonging to the factor <code>visual</code> and those belonging to the factor <code>speed</code>, as well as for the observed association between items <code>x3</code> and <code>x5</code>.</p>
<p>If we believe that the model misses meaningful associations between items and non-target constructs represented by the latent factors, we might specify cross-loadings. If we believe that the model fails to account for shared sources of influence on the indicators that are unrelated to the factors, such as wording effects or context, we would specify residual covariances <span class="citation" data-cites="asparouhov_bayesian_2015">(<a href="#ref-asparouhov_bayesian_2015" role="doc-biblioref">Asparouhov, Muthén, and Morin 2015</a>)</span>. In either case, we should explain the decision. Here, we will specify the covariances.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb24"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb24-1"><a href="#cb24-1" aria-hidden="true" tabindex="-1"></a><span class="co"># Define models</span></span>
<span id="cb24-2"><a href="#cb24-2" aria-hidden="true" tabindex="-1"></a>three_factor_model <span class="ot"><-</span> <span class="st">'</span></span>
<span id="cb24-3"><a href="#cb24-3" aria-hidden="true" tabindex="-1"></a><span class="st">visual =~ x1 + x2 + x3</span></span>
<span id="cb24-4"><a href="#cb24-4" aria-hidden="true" tabindex="-1"></a><span class="st">textual =~ x4 + x5 + x6</span></span>
<span id="cb24-5"><a href="#cb24-5" aria-hidden="true" tabindex="-1"></a><span class="st">speed =~ x7 + x8 + x9</span></span>
<span id="cb24-6"><a href="#cb24-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb24-7"><a href="#cb24-7" aria-hidden="true" tabindex="-1"></a><span class="st">x1~~x7</span></span>
<span id="cb24-8"><a href="#cb24-8" aria-hidden="true" tabindex="-1"></a><span class="st">x1~~x9</span></span>
<span id="cb24-9"><a href="#cb24-9" aria-hidden="true" tabindex="-1"></a><span class="st">x2~~x7</span></span>
<span id="cb24-10"><a href="#cb24-10" aria-hidden="true" tabindex="-1"></a><span class="st">x3~~x5</span></span>
<span id="cb24-11"><a href="#cb24-11" aria-hidden="true" tabindex="-1"></a><span class="st">x3~~x9</span></span>
<span id="cb24-12"><a href="#cb24-12" aria-hidden="true" tabindex="-1"></a><span class="st">'</span></span>
<span id="cb24-13"><a href="#cb24-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb24-14"><a href="#cb24-14" aria-hidden="true" tabindex="-1"></a>three_factor_cfa_res <span class="ot"><-</span> lavaan<span class="sc">::</span><span class="fu">cfa</span>(<span class="at">model =</span> three_factor_model,</span>
<span id="cb24-15"><a href="#cb24-15" aria-hidden="true" tabindex="-1"></a> <span class="at">data =</span> Data,</span>
<span id="cb24-16"><a href="#cb24-16" aria-hidden="true" tabindex="-1"></a> <span class="at">estimator =</span> <span class="st">'mlr'</span>,</span>
<span id="cb24-17"><a href="#cb24-17" aria-hidden="true" tabindex="-1"></a> <span class="at">std.lv =</span> <span class="cn">TRUE</span>)</span>
<span id="cb24-18"><a href="#cb24-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb24-19"><a href="#cb24-19" aria-hidden="true" tabindex="-1"></a><span class="fu">round</span>(lavaan<span class="sc">::</span><span class="fu">fitMeasures</span>(three_factor_cfa_res, <span class="at">fit.measures =</span> fit_measures), <span class="at">digits =</span> <span class="dv">3</span>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code> chisq.scaled df pvalue.scaled cfi.robust rmsea.robust
39.369 19.000 0.004 0.976 0.060
srmr aic bic bic2
0.043 7482.346 7578.730 7496.273 </code></pre>
</div>
<div class="sourceCode cell-code" id="cb26"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb26-1"><a href="#cb26-1" aria-hidden="true" tabindex="-1"></a>lavaan<span class="sc">::</span><span class="fu">lavResiduals</span>(three_factor_cfa_res)<span class="sc">$</span>cov</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code> x1 x2 x3 x4 x5 x6 x7 x8 x9
x1 0.027
x2 -0.006 0.007
x3 0.043 0.118 0.023
x4 0.079 -0.011 -0.057 0.000
x5 0.000 -0.024 -0.045 0.015 0.014
x6 0.066 0.030 -0.016 -0.008 0.010 0.000
x7 -0.019 0.000 -0.076 0.026 -0.045 -0.025 -0.006
x8 -0.015 -0.041 0.011 -0.067 -0.034 -0.022 0.027 0.000
x9 0.043 0.095 0.016 0.062 0.082 0.070 -0.044 -0.004 -0.001</code></pre>
</div>
</div>
<p>After having introduced the residual covariances, the model still fails to pass the exact-fit test but has acceptable values on the approximate fit indices, and there are no other correlation residuals that require our attention. We can check the value of the residual correlations (not correlation residuals!) by running <code>standardizedSolution(three_factor_cfa_res)</code> and subsetting the rows.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb28"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb28-1"><a href="#cb28-1" aria-hidden="true" tabindex="-1"></a>standardized_solution <span class="ot"><-</span> lavaan<span class="sc">::</span><span class="fu">standardizedSolution</span>(three_factor_cfa_res)</span>
<span id="cb28-2"><a href="#cb28-2" aria-hidden="true" tabindex="-1"></a><span class="fu">subset</span>(standardized_solution, <span class="fu">grepl</span>(<span class="st">"~~"</span>, op) <span class="sc">&</span> </span>
<span id="cb28-3"><a href="#cb28-3" aria-hidden="true" tabindex="-1"></a> <span class="fu">grepl</span>(<span class="st">"^x[0-9]+$"</span>, lhs) <span class="sc">&</span> </span>
<span id="cb28-4"><a href="#cb28-4" aria-hidden="true" tabindex="-1"></a> <span class="fu">grepl</span>(<span class="st">"^x[0-9]+$"</span>, rhs) <span class="sc">&</span> </span>
<span id="cb28-5"><a href="#cb28-5" aria-hidden="true" tabindex="-1"></a> lhs <span class="sc">!=</span> rhs)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code> lhs op rhs est.std se z pvalue ci.lower ci.upper
10 x1 ~~ x7 -0.226 0.110 -2.061 0.039 -0.441 -0.011
11 x1 ~~ x9 0.285 0.102 2.799 0.005 0.085 0.485
12 x2 ~~ x7 -0.265 0.066 -3.991 0.000 -0.395 -0.135
13 x3 ~~ x5 -0.216 0.076 -2.860 0.004 -0.364 -0.068
14 x3 ~~ x9 0.254 0.065 3.918 0.000 0.127 0.381</code></pre>
</div>
</div>
<div class="no-row-height column-margin column-container"><div class="">
<p>We use <code>subset()</code> and <code>grepl()</code> to find rows that:</p>
<ul>
<li>have <code>~~</code> in the column <code>op</code></li>
<li>start with <code>x</code> followed by a numeric value in the columns <code>lhs</code> and <code>rhs</code></li>
<li>have different values in the columns <code>lhs</code> and <code>rhs</code> (because we are interested in the correlations)<br>
</li>
</ul>
</div></div><p>Now, we will inspect factor loadings and the correlation structure between the factors.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb30"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb30-1"><a href="#cb30-1" aria-hidden="true" tabindex="-1"></a>lavaan<span class="sc">::</span><span class="fu">lavInspect</span>(three_factor_cfa_res, <span class="st">"std"</span>)<span class="sc">$</span>lambda</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code> visual textul speed
x1 0.747 0.000 0.000
x2 0.412 0.000 0.000
x3 0.546 0.000 0.000
x4 0.000 0.849 0.000
x5 0.000 0.852 0.000
x6 0.000 0.840 0.000
x7 0.000 0.000 0.623
x8 0.000 0.000 0.736
x9 0.000 0.000 0.616</code></pre>
</div>
<div class="sourceCode cell-code" id="cb32"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb32-1"><a href="#cb32-1" aria-hidden="true" tabindex="-1"></a><span class="co"># interfactor correlation</span></span>
<span id="cb32-2"><a href="#cb32-2" aria-hidden="true" tabindex="-1"></a>lavaan<span class="sc">::</span><span class="fu">lavInspect</span>(three_factor_cfa_res, <span class="st">"std"</span>)<span class="sc">$</span>psi</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code> visual textul speed
visual 1.000
textual 0.470 1.000
speed 0.440 0.278 1.000</code></pre>
</div>
</div>
<p>We can see that all the standardized factor loadings have non-trivial values (greater than .3) and vary in magnitude. Correlations between the factors range from .470 (<code>textual</code> and <code>visual</code>) to .278 (<code>speed</code> and <code>textual</code>).</p>
</section>
</section>
<section id="descriptive-statistics-of-indicators-reliability-and-criterion-validity" class="level2">
<h2 class="anchored" data-anchor-id="descriptive-statistics-of-indicators-reliability-and-criterion-validity">Descriptive statistics of indicators, reliability, and criterion validity</h2>
<p>In this section, we will take a closer look at the indicators themselves and the observed scores. First, we will compute descriptive statistics for the indicators:</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb34"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb34-1"><a href="#cb34-1" aria-hidden="true" tabindex="-1"></a>psych<span class="sc">::</span><span class="fu">describe</span>(Data[ , <span class="fu">unlist</span>(lookup_table<span class="sc">$</span>item)])[, <span class="fu">c</span>(<span class="st">"mean"</span>, <span class="st">"sd"</span>, <span class="st">"skew"</span>, <span class="st">"kurtosis"</span>, <span class="st">"n"</span>)]</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code> mean sd skew kurtosis n
x1 4.94 1.17 -0.25 0.31 301
x2 6.09 1.18 0.47 0.33 301
x3 2.25 1.13 0.38 -0.91 301
x4 3.06 1.16 0.27 0.08 301
x5 4.34 1.29 -0.35 -0.55 301
x6 2.19 1.10 0.86 0.82 301
x7 4.19 1.09 0.25 -0.31 301
x8 5.53 1.01 0.53 1.17 301
x9 5.37 1.01 0.20 0.29 301</code></pre>
</div>
</div>
<p>Then, we calculate the reliability coefficients. To assess reliability, scholars usually compute Cronbach’s α. However, this coefficient is not appropriate when the indicators are congeneric. If the factor loadings vary substantially, we should compute McDonald’s ω<sub>h</sub> <span class="citation" data-cites="zinbarg_cronbachs_2005">(<a href="#ref-zinbarg_cronbachs_2005" role="doc-biblioref">Zinbarg et al. 2005</a>)</span>. Still, we will compute both coefficients for the sake of demonstration. For Cronbach’s α, we will compute the median and 95% confidence interval.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb36"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb36-1"><a href="#cb36-1" aria-hidden="true" tabindex="-1"></a><span class="co"># Creating a vector with subscales and iterating the calculations over it</span></span>
<span id="cb36-2"><a href="#cb36-2" aria-hidden="true" tabindex="-1"></a>subscales <span class="ot"><-</span> <span class="fu">unique</span>(lookup_table<span class="sc">$</span>subscale)</span>
<span id="cb36-3"><a href="#cb36-3" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span> (subscale <span class="cf">in</span> subscales){</span>
<span id="cb36-4"><a href="#cb36-4" aria-hidden="true" tabindex="-1"></a>alpha_i <span class="ot"><-</span> psych<span class="sc">::</span><span class="fu">alpha</span>(Data[, lookup_table[lookup_table<span class="sc">$</span>subscale <span class="sc">==</span> subscale, <span class="st">"item"</span>]],</span>
<span id="cb36-5"><a href="#cb36-5" aria-hidden="true" tabindex="-1"></a> <span class="at">n.iter =</span> <span class="dv">1000</span>)</span>
<span id="cb36-6"><a href="#cb36-6" aria-hidden="true" tabindex="-1"></a><span class="co"># Rounding </span></span>
<span id="cb36-7"><a href="#cb36-7" aria-hidden="true" tabindex="-1"></a>alpha_sum <span class="ot"><-</span> <span class="fu">round</span>(alpha_i[[<span class="st">"boot.ci"</span>]], <span class="dv">2</span>)</span>
<span id="cb36-8"><a href="#cb36-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb36-9"><a href="#cb36-9" aria-hidden="true" tabindex="-1"></a><span class="co"># Print the subscale name</span></span>
<span id="cb36-10"><a href="#cb36-10" aria-hidden="true" tabindex="-1"></a><span class="fu">cat</span>(<span class="st">"Subscale:"</span>, subscale, <span class="st">"</span><span class="sc">\n</span><span class="st">"</span>)</span>
<span id="cb36-11"><a href="#cb36-11" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb36-12"><a href="#cb36-12" aria-hidden="true" tabindex="-1"></a><span class="co"># Print the corresponding alpha values</span></span>
<span id="cb36-13"><a href="#cb36-13" aria-hidden="true" tabindex="-1"></a><span class="fu">print</span>(alpha_sum)</span>
<span id="cb36-14"><a href="#cb36-14" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb36-15"><a href="#cb36-15" aria-hidden="true" tabindex="-1"></a><span class="co"># Add an empty line for better readability between subscales</span></span>
<span id="cb36-16"><a href="#cb36-16" aria-hidden="true" tabindex="-1"></a><span class="fu">cat</span>(<span class="st">"</span><span class="sc">\n</span><span class="st">"</span>)</span>
<span id="cb36-17"><a href="#cb36-17" aria-hidden="true" tabindex="-1"></a>}</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>Subscale: visual
2.5% 50% 97.5%
0.55 0.63 0.69
Subscale: textual
2.5% 50% 97.5%
0.86 0.88 0.90
Subscale: speed
2.5% 50% 97.5%
0.61 0.69 0.75 </code></pre>
</div>
<div class="sourceCode cell-code" id="cb38"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb38-1"><a href="#cb38-1" aria-hidden="true" tabindex="-1"></a><span class="co"># McDonalds omega hierarchical</span></span>
<span id="cb38-2"><a href="#cb38-2" aria-hidden="true" tabindex="-1"></a>omegas <span class="ot"><-</span> semTools<span class="sc">::</span><span class="fu">compRelSEM</span>(three_factor_cfa_res)</span>
<span id="cb38-3"><a href="#cb38-3" aria-hidden="true" tabindex="-1"></a><span class="fu">round</span>(omegas, <span class="dv">2</span>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code> visual textual speed
0.55 0.88 0.70 </code></pre>
</div>
</div>
<p>The results suggest that the reliability for the “visual” scale is not satisfactory.</p>
<p>Lastly, we will investigate the criterion validity. For this, we will compute correlations between the mean scale scores and four variables that we have in the dataset: gender, age, school, and grade.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb40"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb40-1"><a href="#cb40-1" aria-hidden="true" tabindex="-1"></a><span class="co"># Creating unweighted means </span></span>
<span id="cb40-2"><a href="#cb40-2" aria-hidden="true" tabindex="-1"></a>subscales <span class="ot"><-</span> <span class="fu">unique</span>(lookup_table<span class="sc">$</span>subscale)</span>
<span id="cb40-3"><a href="#cb40-3" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span>(subscale <span class="cf">in</span> subscales) {</span>
<span id="cb40-4"><a href="#cb40-4" aria-hidden="true" tabindex="-1"></a> subscale_name <span class="ot"><-</span> <span class="fu">paste</span>(subscale, <span class="st">"mean"</span>, <span class="at">sep =</span> <span class="st">"_"</span>)</span>
<span id="cb40-5"><a href="#cb40-5" aria-hidden="true" tabindex="-1"></a> items <span class="ot"><-</span> lookup_table[lookup_table<span class="sc">$</span>subscale <span class="sc">==</span> subscale, <span class="st">"item"</span>]</span>
<span id="cb40-6"><a href="#cb40-6" aria-hidden="true" tabindex="-1"></a> mean_score <span class="ot"><-</span> <span class="fu">rowMeans</span>(Data[, items], <span class="at">na.rm =</span> <span class="cn">FALSE</span>)</span>
<span id="cb40-7"><a href="#cb40-7" aria-hidden="true" tabindex="-1"></a> Data[, subscale_name] <span class="ot"><-</span> mean_score</span>
<span id="cb40-8"><a href="#cb40-8" aria-hidden="true" tabindex="-1"></a> }</span>
<span id="cb40-9"><a href="#cb40-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-10"><a href="#cb40-10" aria-hidden="true" tabindex="-1"></a><span class="co"># Transform school variable to a numeric variable</span></span>
<span id="cb40-11"><a href="#cb40-11" aria-hidden="true" tabindex="-1"></a>Data<span class="sc">$</span>school_numeric <span class="ot"><-</span> <span class="fu">as.numeric</span>(Data<span class="sc">$</span>school)</span>
<span id="cb40-12"><a href="#cb40-12" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb40-13"><a href="#cb40-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-14"><a href="#cb40-14" aria-hidden="true" tabindex="-1"></a><span class="co"># Define variables for correlational analyses</span></span>
<span id="cb40-15"><a href="#cb40-15" aria-hidden="true" tabindex="-1"></a>cor_variables <span class="ot"><-</span> <span class="fu">c</span>(<span class="st">"visual_mean"</span>, <span class="st">"textual_mean"</span>, <span class="st">"speed_mean"</span>,</span>
<span id="cb40-16"><a href="#cb40-16" aria-hidden="true" tabindex="-1"></a> <span class="st">"sex"</span>, <span class="st">"age"</span>, <span class="st">"school_numeric"</span>, <span class="st">"grade"</span>)</span>
<span id="cb40-17"><a href="#cb40-17" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-18"><a href="#cb40-18" aria-hidden="true" tabindex="-1"></a><span class="co"># Estimate correlations & p-values</span></span>
<span id="cb40-19"><a href="#cb40-19" aria-hidden="true" tabindex="-1"></a>cor_coef <span class="ot"><-</span> Hmisc<span class="sc">::</span><span class="fu">rcorr</span>(<span class="fu">as.matrix</span>(Data[, cor_variables]))<span class="sc">$</span>r</span>
<span id="cb40-20"><a href="#cb40-20" aria-hidden="true" tabindex="-1"></a>cor_pval <span class="ot"><-</span> Hmisc<span class="sc">::</span><span class="fu">rcorr</span>(<span class="fu">as.matrix</span>(Data[, cor_variables]))<span class="sc">$</span>P</span>
<span id="cb40-21"><a href="#cb40-21" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-22"><a href="#cb40-22" aria-hidden="true" tabindex="-1"></a><span class="co"># Filtering rows and columns</span></span>
<span id="cb40-23"><a href="#cb40-23" aria-hidden="true" tabindex="-1"></a>cor_coef <span class="ot"><-</span> cor_coef[<span class="sc">!</span><span class="fu">grepl</span>(<span class="st">"mean"</span>, <span class="fu">rownames</span>(cor_coef)),<span class="fu">grepl</span>(<span class="st">"mean"</span>, <span class="fu">colnames</span>(cor_coef))]</span>
<span id="cb40-24"><a href="#cb40-24" aria-hidden="true" tabindex="-1"></a>cor_pval <span class="ot"><-</span> cor_pval[<span class="sc">!</span><span class="fu">grepl</span>(<span class="st">"mean"</span>, <span class="fu">rownames</span>(cor_pval)),<span class="fu">grepl</span>(<span class="st">"mean"</span>, <span class="fu">colnames</span>(cor_pval))]</span>
<span id="cb40-25"><a href="#cb40-25" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-26"><a href="#cb40-26" aria-hidden="true" tabindex="-1"></a><span class="co"># Formatting the output to two and three decimal places</span></span>
<span id="cb40-27"><a href="#cb40-27" aria-hidden="true" tabindex="-1"></a>cor_coef <span class="ot"><-</span> <span class="fu">as.data.frame</span>(cor_coef) <span class="sc">%>%</span></span>
<span id="cb40-28"><a href="#cb40-28" aria-hidden="true" tabindex="-1"></a> <span class="fu">mutate</span>(<span class="fu">across</span>(<span class="fu">everything</span>(), <span class="sc">~</span> <span class="fu">sprintf</span>(<span class="st">"%.2f"</span>, .)))</span>
<span id="cb40-29"><a href="#cb40-29" aria-hidden="true" tabindex="-1"></a>cor_pval <span class="ot"><-</span> <span class="fu">as.data.frame</span>(cor_pval) <span class="sc">%>%</span></span>
<span id="cb40-30"><a href="#cb40-30" aria-hidden="true" tabindex="-1"></a> <span class="fu">mutate</span>(<span class="fu">across</span>(<span class="fu">everything</span>(), <span class="sc">~</span> <span class="fu">sprintf</span>(<span class="st">"%.3f"</span>, .)))</span>
<span id="cb40-31"><a href="#cb40-31" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-32"><a href="#cb40-32" aria-hidden="true" tabindex="-1"></a>cor_coef</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code> visual_mean textual_mean speed_mean
sex -0.17 0.07 0.05
age -0.00 -0.23 0.21
school_numeric 0.05 -0.27 0.14
grade 0.20 0.20 0.37</code></pre>
</div>
<div class="sourceCode cell-code" id="cb42"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb42-1"><a href="#cb42-1" aria-hidden="true" tabindex="-1"></a>cor_pval </span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code> visual_mean textual_mean speed_mean
sex 0.004 0.223 0.358
age 0.979 0.000 0.000
school_numeric 0.345 0.000 0.016
grade 0.001 0.001 0.000</code></pre>
</div>
</div>
<p>Correlations are small to moderate, and not all of them are significant. We see that the “visual” scale correlates with gender and grade, while the “textual” and “speed” scales correlate with age, school, and grade.</p>
</section>
<section id="descriptive-statistics-of-the-scales" class="level2">
<h2 class="anchored" data-anchor-id="descriptive-statistics-of-the-scales">Descriptive statistics of the scales</h2>
<p>The final part of this tutorial consists of computing descriptive statistics for the scale scores.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb44"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb44-1"><a href="#cb44-1" aria-hidden="true" tabindex="-1"></a>psych<span class="sc">::</span><span class="fu">describe</span>(Data[, <span class="fu">c</span>(<span class="st">"visual_mean"</span>, <span class="st">"textual_mean"</span>, <span class="st">"speed_mean"</span>)])[, <span class="fu">c</span>(<span class="st">"mean"</span>, <span class="st">"sd"</span>, <span class="st">"skew"</span>, <span class="st">"kurtosis"</span>, <span class="st">"n"</span>)]</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code> mean sd skew kurtosis n
visual_mean 4.42 0.88 0.18 -0.09 301
textual_mean 3.20 1.07 0.16 -0.16 301
speed_mean 5.03 0.81 0.14 0.12 301</code></pre>
</div>
</div>
</section>
<div id="quarto-appendix" class="default"><section class="quarto-appendix-contents" role="doc-bibliography" id="quarto-bibliography"><h2 class="anchored quarto-appendix-heading">References</h2><div id="refs" class="references csl-bib-body hanging-indent" data-entry-spacing="0" role="list">
<div id="ref-asparouhov_bayesian_2015" class="csl-entry" role="listitem">
Asparouhov, Tihomir, Bengt Muthén, and Alexandre J. S. Morin. 2015. <span>“Bayesian <span>Structural</span> <span>Equation</span> <span>Modeling</span> <span>With</span> <span>Cross</span>-<span>Loadings</span> and <span>Residual</span> <span>Covariances</span>: <span>Comments</span> on <span>Stromeyer</span> Et Al.”</span> <em>Journal of Management</em> 41 (6): 1561–77. <a href="https://doi.org/10.1177/0149206315591075">https://doi.org/10.1177/0149206315591075</a>.
</div>
<div id="ref-bollen_latent_2002" class="csl-entry" role="listitem">
Bollen, Kenneth A. 2002. <span>“Latent <span>Variables</span> in <span>Psychology</span> and the <span>Social</span> <span>Sciences</span>.”</span> <em>Annual Review of Psychology</em> 53 (1): 605–34. <a href="https://doi.org/10.1146/annurev.psych.53.100901.135239">https://doi.org/10.1146/annurev.psych.53.100901.135239</a>.
</div>
<div id="ref-byrne_structural_1994" class="csl-entry" role="listitem">
Byrne, Barbara M. 1994. <em>Structural Equation Modelling with EQS and EQS/Windows: Basic Concepts, Applications, and Programming</em>. 1st ed. Sage.
</div>
<div id="ref-fabrigar_exploratory_2012" class="csl-entry" role="listitem">
Fabrigar, Leandre R., and Duane Theodore Wegener. 2012. <em>Exploratory Factor Analysis</em>. Understanding Statistics. Oxford, New York: Oxford University Press.
</div>
<div id="ref-groskurth_why_2023" class="csl-entry" role="listitem">
Groskurth, Katharina, Matthias Bluemke, and Clemens M. Lechner. 2023. <span>“Why We Need to Abandon Fixed Cutoffs for Goodness-of-Fit Indices: <span>An</span> Extensive Simulation and Possible Solutions.”</span> <em>Behavior Research Methods</em> 56 (4): 3891–3914. <a href="https://doi.org/10.3758/s13428-023-02193-3">https://doi.org/10.3758/s13428-023-02193-3</a>.
</div>
<div id="ref-hu_cutoff_1999" class="csl-entry" role="listitem">
Hu, Li‐tze, and Peter M. Bentler. 1999. <span>“Cutoff Criteria for Fit Indexes in Covariance Structure Analysis: <span>Conventional</span> Criteria Versus New Alternatives.”</span> <em>Structural Equation Modeling: A Multidisciplinary Journal</em> 6 (1): 1–55. <a href="https://doi.org/10.1080/10705519909540118">https://doi.org/10.1080/10705519909540118</a>.
</div>
<div id="ref-kline_principles_2016" class="csl-entry" role="listitem">
Kline, Rex B. 2016. <em>Principles and Practice of Structural Equation Modeling</em>. Fourth edition. Methodology in the Social Sciences. New York: The Guilford Press.
</div>
<div id="ref-mcneish_dynamic_2023" class="csl-entry" role="listitem">
McNeish, Daniel, and Melissa G. Wolf. 2023. <span>“Dynamic Fit Index Cutoffs for Confirmatory Factor Analysis Models.”</span> <em>Psychological Methods</em> 28 (1): 61–88. <a href="https://doi.org/10.1037/met0000425">https://doi.org/10.1037/met0000425</a>.
</div>
<div id="ref-russell_search_2002" class="csl-entry" role="listitem">
Russell, Daniel W. 2002. <span>“In <span>Search</span> of <span>Underlying</span> <span>Dimensions</span>: <span>The</span> <span>Use</span> (and <span>Abuse</span>) of <span>Factor</span> <span>Analysis</span> in <span>Personality</span> and <span>Social</span> <span>Psychology</span> <span>Bulletin</span>.”</span> <em>Personality and Social Psychology Bulletin</em> 28 (12): 1629–46. <a href="https://doi.org/10.1177/014616702237645">https://doi.org/10.1177/014616702237645</a>.
</div>
<div id="ref-van_der_eijk_risky_2015" class="csl-entry" role="listitem">
Van Der Eijk, Cees, and Jonathan Rose. 2015. <span>“Risky <span>Business</span>: <span>Factor</span> <span>Analysis</span> of <span>Survey</span> <span>Data</span> – <span>Assessing</span> the <span>Probability</span> of <span>Incorrect</span> <span>Dimensionalisation</span>.”</span> <em>PLOS ONE</em> 10 (3): e0118900. <a href="https://doi.org/10.1371/journal.pone.0118900">https://doi.org/10.1371/journal.pone.0118900</a>.
</div>
<div id="ref-widaman_thinking_2023" class="csl-entry" role="listitem">
Widaman, Keith F., and William Revelle. 2023. <span>“Thinking <span>About</span> <span>Sum</span> <span>Scores</span> <span>Yet</span> <span>Again</span>, <span>Maybe</span> the <span>Last</span> <span>Time</span>, <span>We</span> <span>Don</span>’t <span>Know</span>, <span>Oh</span> <span>No</span> . . .: <span>A</span> <span>Comment</span> On.”</span> <em>Educational and Psychological Measurement</em>, October, 00131644231205310. <a href="https://doi.org/10.1177/00131644231205310">https://doi.org/10.1177/00131644231205310</a>.
</div>
<div id="ref-zinbarg_cronbachs_2005" class="csl-entry" role="listitem">
Zinbarg, Richard E., William Revelle, Iftah Yovel, and Wen Li. 2005. <span>“Cronbach’s α, <span>Revelle</span>’s β, and <span>Mcdonald</span>’s ω<span>H</span>: Their Relations with Each Other and Two Alternative Conceptualizations of Reliability.”</span> <em>Psychometrika</em> 70 (1): 123–33. <a href="https://doi.org/10.1007/s11336-003-0974-7">https://doi.org/10.1007/s11336-003-0974-7</a>.
</div>
</div></section><section id="footnotes" class="footnotes footnotes-end-of-document" role="doc-endnotes"><h2 class="anchored quarto-appendix-heading">Footnotes</h2>
<ol>
<li id="fn1"><p>If you are interested in the details of exploratory factor analysis, you might want to check the book by <span class="citation" data-cites="fabrigar_exploratory_2012">Fabrigar and Wegener (<a href="#ref-fabrigar_exploratory_2012" role="doc-biblioref">2012</a>)</span><a href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>We could choose other identification constraints. For more details, see <span class="citation" data-cites="kline_principles_2016">Kline (<a href="#ref-kline_principles_2016" role="doc-biblioref">2016</a>)</span><a href="#fnref2" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn3"><p>Since we use MLR, we also use the robust versions of the fit indices<a href="#fnref3" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn4"><p>Evaluation of the local model fit often highlights the same model misspecifications as the inspection of modification indices. Yet, these two procedures have different premises. Inspection of correlation residuals addresses the question of the violation of the conditional independence assumption <span class="citation" data-cites="bollen_latent_2002">(indicators should be independent conditional on the latent variables, see <a href="#ref-bollen_latent_2002" role="doc-biblioref">Bollen 2002</a>)</span>. With modification indices, we investigate factors that can improve model fit. We prefer the former, as answering the question of the independence assumption is more meaningful than merely improving the fit of the model.<a href="#fnref4" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section><section class="quarto-appendix-contents" id="quarto-reuse"><h2 class="anchored quarto-appendix-heading">Reuse</h2><div class="quarto-appendix-contents"><div><a rel="license" href="https://creativecommons.org/licenses/by-nc/4.0/">CC BY-NC 4.0</a></div></div></section><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">BibTeX citation:</div><pre class="sourceCode code-with-copy quarto-appendix-bibtex"><code class="sourceCode bibtex">@misc{koc2024,
author = {Koc, Piotr and Urban, Julian and Grüning, David},
publisher = {GESIS – Leibniz Institute for the Social Sciences},
title = {Basic {Analysis} for {Scale} {Archiving}},
date = {2024},
urldate = {},
url = {https://zis.gesis.org/infotexte/GuidelineMaterials.html},
langid = {en}
}
</code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-koc2024" class="csl-entry quarto-appendix-citeas" role="listitem">
Koc, Piotr, Julian Urban, and David Grüning. 2024. <span>“Basic Analysis
for Scale Archiving .”</span> <em>ZIS R-Tutorials</em>. GESIS – Leibniz
Institute for the Social Sciences. <a href="https://zis.gesis.org/infotexte/GuidelineMaterials.html">https://zis.gesis.org/infotexte/GuidelineMaterials.html</a>.
</div></div></section></div></main>
<!-- /main column -->
<script id="quarto-html-after-body" type="application/javascript">
window.document.addEventListener("DOMContentLoaded", function (event) {
const toggleBodyColorMode = (bsSheetEl) => {
const mode = bsSheetEl.getAttribute("data-mode");
const bodyEl = window.document.querySelector("body");
if (mode === "dark") {
bodyEl.classList.add("quarto-dark");
bodyEl.classList.remove("quarto-light");
} else {
bodyEl.classList.add("quarto-light");
bodyEl.classList.remove("quarto-dark");
}
}
const toggleBodyColorPrimary = () => {
const bsSheetEl = window.document.querySelector("link#quarto-bootstrap");
if (bsSheetEl) {
toggleBodyColorMode(bsSheetEl);
}
}
toggleBodyColorPrimary();
const icon = "";
const anchorJS = new window.AnchorJS();
anchorJS.options = {
placement: 'right',
icon: icon
};
anchorJS.add('.anchored');
const isCodeAnnotation = (el) => {
for (const clz of el.classList) {
if (clz.startsWith('code-annotation-')) {
return true;
}
}
return false;
}
const clipboard = new window.ClipboardJS('.code-copy-button', {
text: function(trigger) {
const codeEl = trigger.previousElementSibling.cloneNode(true);
for (const childEl of codeEl.children) {
if (isCodeAnnotation(childEl)) {
childEl.remove();
}
}
return codeEl.innerText;
}
});
clipboard.on('success', function(e) {
// button target
const button = e.trigger;
// don't keep focus
button.blur();
// flash "checked"
button.classList.add('code-copy-button-checked');
var currentTitle = button.getAttribute("title");
button.setAttribute("title", "Copied!");
let tooltip;
if (window.bootstrap) {
button.setAttribute("data-bs-toggle", "tooltip");
button.setAttribute("data-bs-placement", "left");
button.setAttribute("data-bs-title", "Copied!");
tooltip = new bootstrap.Tooltip(button,
{ trigger: "manual",
customClass: "code-copy-button-tooltip",
offset: [0, -8]});
tooltip.show();
}
setTimeout(function() {
if (tooltip) {
tooltip.hide();
button.removeAttribute("data-bs-title");
button.removeAttribute("data-bs-toggle");
button.removeAttribute("data-bs-placement");
}
button.setAttribute("title", currentTitle);
button.classList.remove('code-copy-button-checked');
}, 1000);
// clear code selection
e.clearSelection();
});
var localhostRegex = new RegExp(/^(?:http|https):\/\/localhost\:?[0-9]*\//);
var mailtoRegex = new RegExp(/^mailto:/);
var filterRegex = new RegExp('/' + window.location.host + '/');
var isInternal = (href) => {
return filterRegex.test(href) || localhostRegex.test(href) || mailtoRegex.test(href);
}
// Inspect non-navigation links and adorn them if external
var links = window.document.querySelectorAll('a[href]:not(.nav-link):not(.navbar-brand):not(.toc-action):not(.sidebar-link):not(.sidebar-item-toggle):not(.pagination-link):not(.no-external):not([aria-hidden]):not(.dropdown-item):not(.quarto-navigation-tool)');
for (var i=0; i<links.length; i++) {
const link = links[i];
if (!isInternal(link.href)) {
// undo the damage that might have been done by quarto-nav.js in the case of
// links that we want to consider external
if (link.dataset.originalHref !== undefined) {
link.href = link.dataset.originalHref;
}
}
}
function tippyHover(el, contentFn, onTriggerFn, onUntriggerFn) {
const config = {
allowHTML: true,
maxWidth: 500,
delay: 100,
arrow: false,
appendTo: function(el) {
return el.parentElement;
},
interactive: true,
interactiveBorder: 10,
theme: 'quarto',
placement: 'bottom-start',
};
if (contentFn) {
config.content = contentFn;
}
if (onTriggerFn) {
config.onTrigger = onTriggerFn;
}
if (onUntriggerFn) {
config.onUntrigger = onUntriggerFn;
}
window.tippy(el, config);
}
const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]');
for (var i=0; i<noterefs.length; i++) {
const ref = noterefs[i];
tippyHover(ref, function() {
// use id or data attribute instead here
let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href');
try { href = new URL(href).hash; } catch {}
const id = href.replace(/^#\/?/, "");
const note = window.document.getElementById(id);
if (note) {
return note.innerHTML;
} else {
return "";
}
});
}
const xrefs = window.document.querySelectorAll('a.quarto-xref');
const processXRef = (id, note) => {
// Strip column container classes
const stripColumnClz = (el) => {
el.classList.remove("page-full", "page-columns");
if (el.children) {
for (const child of el.children) {
stripColumnClz(child);
}
}
}
stripColumnClz(note)
if (id === null || id.startsWith('sec-')) {
// Special case sections, only their first couple elements
const container = document.createElement("div");
if (note.children && note.children.length > 2) {
container.appendChild(note.children[0].cloneNode(true));
for (let i = 1; i < note.children.length; i++) {
const child = note.children[i];
if (child.tagName === "P" && child.innerText === "") {
continue;
} else {
container.appendChild(child.cloneNode(true));
break;
}
}
if (window.Quarto?.typesetMath) {
window.Quarto.typesetMath(container);
}
return container.innerHTML
} else {
if (window.Quarto?.typesetMath) {
window.Quarto.typesetMath(note);
}
return note.innerHTML;
}
} else {
// Remove any anchor links if they are present
const anchorLink = note.querySelector('a.anchorjs-link');
if (anchorLink) {
anchorLink.remove();
}
if (window.Quarto?.typesetMath) {
window.Quarto.typesetMath(note);
}
// TODO in 1.5, we should make sure this works without a callout special case
if (note.classList.contains("callout")) {
return note.outerHTML;
} else {
return note.innerHTML;
}
}
}
for (var i=0; i<xrefs.length; i++) {
const xref = xrefs[i];
tippyHover(xref, undefined, function(instance) {
instance.disable();
let url = xref.getAttribute('href');
let hash = undefined;
if (url.startsWith('#')) {
hash = url;
} else {
try { hash = new URL(url).hash; } catch {}
}
if (hash) {
const id = hash.replace(/^#\/?/, "");
const note = window.document.getElementById(id);
if (note !== null) {
try {
const html = processXRef(id, note.cloneNode(true));
instance.setContent(html);
} finally {
instance.enable();
instance.show();