11  Konfirmatorisk faktoranalys

CFA

Code
library(foreign)
library(readxl)
library(RISEkbmRasch) # devtools::install_github("pgmj/RISEkbmRasch")
library(grateful) # devtools::install_github("Pakillo/grateful")
library(lavaan)
library(lavaanPlot)


### some commands exist in multiple packages, here we define preferred ones that are frequently used
select <- dplyr::select
count <- dplyr::count
recode <- car::recode
rename <- dplyr::rename

# file paths will need to have "../" added at the beginning to be able to render document

# get itemlabels
itemlabels <- read_excel("../data/Itemlabels.xlsx") %>% 
  select(!Dimension)

spssDatafil <- "../data/2023-04-26 Prevent OSA-enkat.sav"

# read SurveyMonkey data
df <- read.spss(spssDatafil, to.data.frame = TRUE) %>% 
  select(starts_with("q00", ignore.case = FALSE)) %>% 
  rename(Kön = q0002,
         Ålder = q0001,
         Bransch = q0003,
         Hemarbete = q0004) %>% 
  select(!q0014)


# SPSS format provides itemlabels too, we can save them in a dataframe
spssLabels <- df %>% attr('variable.labels') %>% as.data.frame()

dif.kön <- df$Kön
dif.ålder <- df$Ålder
dif.bransch <- df$Bransch
dif.hemarbete <- df$Hemarbete

df <- df %>%
  select(starts_with("q00"))

names(df) <- itemlabels$itemnr

11.1 Modell 1 - alla items

Code
### specify model
# AO is skipped for now due to low variation in data
# AO =~ ao1 + ao2 + ao3 + ao4 + ao5
# KunskapUtv also skipped

allItems <- "BelastKrav =~ abk1+abk2+abk3+abk4+abk5+abk6
             MöjlPåverka =~ mp1+ mp2+ mp3+ mp4+ mp5
             Stöd =~ st1+st2+st3+st4+st5+st6+st7
             Återhämtning =~ å1+å2+å3+å4+å5
             Ledarskap =~ ls1+ls2+ls3+ls4+ls5+ls6
             KränkandeB =~ kb1+kb2+kb3+kb4+kb5+kb6+kb7
             PsykTrygg =~ pt1+pt2+pt3+pt4+pt5+pt6+pt7"

CFAall <- cfa(
  model = allItems,
  data = df,
  rotation = "oblimin",
  estimator = "WLSMV",
  ordered = TRUE
)

11.1.1 Model fit

Code
# create table with model fit metrics
# define fit metrics of interest
fit_metrics_robust <- c("chisq.scaled", "df", "pvalue.scaled", 
                         "cfi.scaled", "tli.scaled", "rmsea.scaled", "srmr")
fitmeasures(CFAall, fit_metrics_robust) %>% 
  rbind() %>% 
  as.data.frame() %>% 
  mutate(across(where(is.numeric),~ round(.x, 3))) %>%
  rename(Chi2 = chisq.scaled,
         p = pvalue.scaled,
         CFI = cfi.scaled,
         TLI = tli.scaled,
         RMSEA = rmsea.scaled,
         SRMR = srmr) %>% 
  formattable(.,
              table.attr = 'class=\"table table-striped\" style="font-size: 14px; font-family: Lato; width: 80%"')
Chi2 df p CFI TLI RMSEA SRMR
. 3074.269 839 0 0.917 0.911 0.077 0.074

11.1.2 Kovarians

Samband mellan faktorer, sorterat på störst korrelation.

Code
CFAout <- summary(CFAall)

CFAout[["pe"]] %>% 
  filter(op == "~~") %>% 
  slice(56:83) %>% 
  mutate(across(where(is.numeric),~ round(.x, 3))) %>%
  select(!exo) %>% 
  arrange(desc(est)) %>% 
  kbl_rise()
lhs op rhs est se z pvalue
Stöd ~~ PsykTrygg 0.530 0.027 19.570 0
Stöd ~~ Ledarskap 0.497 0.026 18.824 0
Ledarskap ~~ PsykTrygg 0.483 0.026 18.303 0
MöjlPåverka ~~ Stöd 0.467 0.027 17.229 0
MöjlPåverka ~~ Återhämtning 0.462 0.026 17.894 0
MöjlPåverka ~~ PsykTrygg 0.460 0.027 16.933 0
KränkandeB ~~ PsykTrygg 0.454 0.035 13.107 0
MöjlPåverka ~~ Ledarskap 0.437 0.028 15.487 0
BelastKrav ~~ PsykTrygg 0.416 0.028 14.685 0
Stöd ~~ Återhämtning 0.371 0.027 13.487 0
Återhämtning ~~ Ledarskap 0.349 0.028 12.317 0
Stöd ~~ KränkandeB 0.331 0.031 10.555 0
Återhämtning ~~ PsykTrygg 0.317 0.029 10.908 0
MöjlPåverka ~~ KränkandeB 0.301 0.033 9.066 0
Ledarskap ~~ KränkandeB 0.283 0.035 7.981 0
Återhämtning ~~ KränkandeB 0.203 0.032 6.259 0

11.1.3 Model plot

Code
lavaanPlot(model = CFAall, 
           coefs = T, stand = T, covs = T,
           node_options = list(fontname = "Helvetica"), 
           edge_options = list(color = "grey"),
           graph_options = list(rankdir = "LR"))

11.1.4 Modification indices

Ordnade efter storlek, störst först.

itemnr item
ao1 Jag vet vilka arbetsuppgifter jag har.
ao2 Jag vet hur mitt arbete ska utföras.
ao3 Jag vet vilka resultat som jag ska uppnå med mitt arbete.
ao4 Det finns tydliga mål för min arbetsgrupp.
ao5 Det finns tydliga mål för min organisation.
abk1 Min arbetsbelastning är rimlig.
abk2 Jag hinner med mina arbetsuppgifter inom min arbetstid.
abk3 Mitt arbete är lagom omväxlande.
abk4 Jag upplever att andras krav på mig är rimliga.
abk5 Jag kan få hjälp om min arbetsbelastning är för hög.
abk6 Mitt arbete är fritt från psykiskt påfrestande arbetsuppgifter.
mp1 Jag har de resurser som behövs för att kunna utföra mina arbetsuppgifter.
mp2 Jag kan prioritera i vilken ordning mina arbetsuppgifter ska utföras.
mp3 Jag har tillräckligt med befogenheter för att kunna utföra mina arbetsuppgifter.
mp4 Jag kan påverka beslut som rör mina arbetsuppgifter.
mp5 Jag kan själv bestämma min arbetstakt.
st1 Jag vet vem jag ska vända mig till för att få stöd och hjälp med att utföra arbetet.
st2 Det finns personer på mitt arbete som jag kan prata förtroligt med.
st3 Vi samarbetar bra på min arbetsplats.
st4 Jag visar uppskattning till mina kollegor för deras arbetsinsatser.
st5 Mina kollegor visar uppskattning för mina arbetsinsatser.
st6 Jag får tekniskt stöd vid behov.
st7 Jag kan få handledning i mitt arbete om jag behöver det.
å1 Jag kan använda raster till att koppla av från arbetet.
å2 Jag har möjlighet att arbeta i lugnare takt efter arbetsintensiva perioder.
å3 Jag har tid för reflektion över hur jag har utfört arbetet.
å4 Jag har ork kvar för att göra andra saker efter arbetsdagens slut.
å5 Jag kan lägga tankar på arbetet åt sidan på min lediga tid.
ls1 Min chef ger mig återkoppling på hur jag utför arbetet.
ls2 Min chef har en god uppfattning om min arbetsbelastning.
ls3 Min chef agerar om jag har allt för mycket arbete att utföra.
ls4 Min chef ser till att alla kommer till tals.
ls5 Min chef hanterar konflikter på ett bra sätt.
ls6 Min chef och jag har tillräckligt med avstämningar.
ku1 Mina kunskaper och färdigheter är till nytta i mitt arbete.
ku2 Jag har tillräckligt med kunskap/färdigheter för att kunna utföra mina arbetsuppgifter.
ku3 Jag har möjlighet att lära mig nya saker när arbetsuppgifterna kräver det.
ku4 Jag har möjlighet till långsiktig kompetensutveckling i mitt arbete.
kb1 Blivit utsatt för att någon undanhåller information som har påverkat din prestation.
kb2 Blivit utsatt för skvaller eller rykten spridda om dig.
kb3 Blivit ignorerad eller exkluderad.
kb4 Fått kränkande eller stötande kommentarer om dig som person, dina attityder eller ditt privatliv.
kb5 Blivit utskälld eller varit föremål för andras aggressiva utbrott.
kb6 Blivit påmind om dina felsteg eller misstag.
kb7 Blivit utsatt för ett otrevligt bemötande när du närmar dig andra.
pt1 Jag har en positiv känsla när jag kommer till jobbet.
pt2 Jag känner mig delaktig i gemenskapen på min arbetsplats.
pt3 Jag kan begå misstag utan att det hålls emot mig.
pt4 Jag kan öppet diskutera olika typer av svårigheter.
pt5 Jag blir inkluderad även om jag tycker annorlunda.
pt6 Mina ansträngningar värdesätts.
pt7 Mina idéer ges tid och uppmärksamhet.

11.1.4.1 Korsladdningar

Med MI > 100.

Code
modificationIndices(CFAall,
                    standardized = T) %>% 
  as.data.frame(row.names = NULL) %>% 
  filter(mi > 100,
         op == "=~") %>% 
  arrange(desc(mi)) %>% 
  mutate(across(where(is.numeric),~ round(.x, 3))) %>%
  kbl_rise(fontsize = 14, width = 75)
lhs op rhs mi epc sepc.lv sepc.all sepc.nox
Stöd =~ abk2 345.697 -0.826 -0.655 -0.655 -0.655
PsykTrygg =~ abk2 332.470 -0.636 -0.526 -0.526 -0.526
Ledarskap =~ abk2 295.057 -0.664 -0.560 -0.560 -0.560
Stöd =~ abk1 239.864 -0.681 -0.541 -0.541 -0.541
MöjlPåverka =~ abk2 238.181 -1.052 -0.848 -0.848 -0.848
PsykTrygg =~ abk1 210.167 -0.498 -0.411 -0.411 -0.411
KränkandeB =~ abk2 180.244 -0.429 -0.375 -0.375 -0.375
MöjlPåverka =~ abk1 179.235 -0.910 -0.734 -0.734 -0.734
PsykTrygg =~ abk3 175.086 0.466 0.385 0.385 0.385
Ledarskap =~ abk1 168.223 -0.485 -0.409 -0.409 -0.409
Ledarskap =~ abk5 166.724 0.453 0.382 0.382 0.382
Stöd =~ abk5 163.547 0.540 0.429 0.429 0.429
Återhämtning =~ mp3 163.512 -0.924 -0.717 -0.717 -0.717
Stöd =~ abk3 156.409 0.577 0.458 0.458 0.458
PsykTrygg =~ abk4 146.929 0.392 0.324 0.324 0.324
BelastKrav =~ mp3 138.262 -0.851 -0.746 -0.746 -0.746
KränkandeB =~ abk4 129.480 0.347 0.304 0.304 0.304
KränkandeB =~ abk1 128.065 -0.366 -0.320 -0.320 -0.320
MöjlPåverka =~ abk4 121.051 0.729 0.587 0.587 0.587
Återhämtning =~ mp5 119.779 0.717 0.556 0.556 0.556
MöjlPåverka =~ abk3 119.457 0.845 0.681 0.681 0.681
PsykTrygg =~ mp5 117.785 -0.532 -0.440 -0.440 -0.440
Stöd =~ abk4 108.393 0.438 0.347 0.347 0.347

11.1.4.2 Residualkorrelationer

Code
modificationIndices(CFAall,
                    standardized = T) %>% 
  as.data.frame(row.names = NULL) %>% 
  filter(mi > 20,
         op == "~~") %>% 
  arrange(desc(mi)) %>% 
  mutate(across(where(is.numeric),~ round(.x, 3))) %>%
  kbl_rise(fontsize = 14, width = 75)
lhs op rhs mi epc sepc.lv sepc.all sepc.nox
abk1 ~~ abk2 380.761 0.375 0.375 1.393 1.393
st4 ~~ st5 252.681 0.380 0.380 0.657 0.657
abk5 ~~ st7 101.134 0.298 0.298 0.719 0.719
abk5 ~~ ls3 91.141 0.266 0.266 0.894 0.894
mp3 ~~ mp4 61.834 0.209 0.209 0.484 0.484
ls4 ~~ ls5 61.424 0.162 0.162 0.592 0.592
abk3 ~~ pt1 54.000 0.264 0.264 0.609 0.609
mp5 ~~ å2 47.294 0.209 0.209 0.646 0.646
pt6 ~~ pt7 45.842 0.124 0.124 0.632 0.632
abk5 ~~ st1 40.605 0.218 0.218 0.572 0.572
abk2 ~~ abk3 37.081 -0.285 -0.285 -0.660 -0.660
kb5 ~~ kb6 36.303 0.222 0.222 0.490 0.490
abk2 ~~ mp4 32.664 -0.242 -0.242 -0.690 -0.690
abk2 ~~ mp3 31.727 -0.251 -0.251 -0.648 -0.648
abk1 ~~ mp3 31.080 -0.240 -0.240 -0.723 -0.723
abk1 ~~ mp4 29.334 -0.208 -0.208 -0.692 -0.692
å2 ~~ å3 27.400 0.121 0.121 0.499 0.499
abk4 ~~ abk5 24.927 -0.168 -0.168 -0.521 -0.521
abk3 ~~ pt7 24.408 0.185 0.185 0.582 0.582
å4 ~~ pt1 24.343 0.180 0.180 0.550 0.550
pt4 ~~ pt5 24.327 0.104 0.104 0.437 0.437
mp3 ~~ å3 24.037 -0.209 -0.209 -0.632 -0.632
abk2 ~~ pt5 22.452 -0.242 -0.242 -0.939 -0.939
abk1 ~~ abk3 20.905 -0.212 -0.212 -0.571 -0.571
st1 ~~ st5 20.726 -0.189 -0.189 -0.441 -0.441
abk3 ~~ abk5 20.661 -0.212 -0.212 -0.440 -0.440
abk2 ~~ pt2 20.591 -0.220 -0.220 -0.703 -0.703
abk1 ~~ pt5 20.246 -0.213 -0.213 -0.964 -0.964
abk2 ~~ st5 20.099 -0.213 -0.213 -0.541 -0.541

11.2 Rasch based model

Items och justerade svarskategorier utifrån Rasch-analyserna.

Code
# recode response categories

df <- df %>% 
  mutate(abk3 = car::recode(abk3,"1=0;2=0;3=1;4=2;5=3"),
         abk2 = car::recode(abk2,"2=1;3=2;4=3;5=4"),
         st1 = recode(st1, "1=0;2=1;3=2;4=3;5=4"),
         st2 = recode(st2, "1=0;2=1;3=1;4=2;5=3"),
         across(kb1:kb7, ~ recode(.x,"3=2;4=2"))
         )

df$mp1<-recode(df$mp1,"1=0;2=1;3=2;4=3;5=4",as.factor=FALSE)
df$mp3<-recode(df$mp3,"1=0;2=1;3=2;4=3;5=4",as.factor=FALSE)
df$mp2<-recode(df$mp2,"1=0;2=1;3=2;4=3;5=4",as.factor=FALSE)
df$mp5<-recode(df$mp5,"2=1;3=2;4=3;5=4",as.factor=FALSE)
Code
raschItems <- "BelastKrav =~ abk2+abk3+abk5+abk6
             MöjlPåverka =~ mp1+mp2+mp3+mp5
             Stöd =~ st1+st2+st5+st6+st7
             Återhämtning =~ å1+å3+å4+å5
             Ledarskap =~ ls1+ls2+ls3+ls5+ls6
             KränkandeB =~ kb2+kb3+kb4+kb5+kb6+kb7
             PsykTrygg =~ pt1+pt2+pt3+pt4+pt6"

CFArasch <- cfa(
  model = raschItems,
  data = df,
  rotation = "oblimin",
  estimator = "WLSMV",
  ordered = TRUE
)

11.2.1 Model fit

Code
# create table with model fit metrics
# define fit metrics of interest
fit_metrics_robust <- c("chisq.scaled", "df", "pvalue.scaled", 
                         "cfi.scaled", "tli.scaled", "rmsea.scaled", "srmr")
fitmeasures(CFArasch, fit_metrics_robust) %>% 
  rbind() %>% 
  as.data.frame() %>% 
  mutate(across(where(is.numeric),~ round(.x, 3))) %>%
  rename(Chi2 = chisq.scaled,
         p = pvalue.scaled,
         CFI = cfi.scaled,
         TLI = tli.scaled,
         RMSEA = rmsea.scaled,
         SRMR = srmr) %>% 
  formattable(.,
              table.attr = 'class=\"table table-striped\" style="font-size: 14px; font-family: Lato; width: 80%"')
Chi2 df p CFI TLI RMSEA SRMR
. 1093.26 474 0 0.957 0.952 0.054 0.056

11.2.2 Kovarians

Samband mellan faktorer, sorterat på störst korrelation.

Code
CFAout2 <- summary(CFArasch)

CFAout2[["pe"]] %>% 
  filter(op == "~~") %>% 
  slice(41:61) %>% 
  mutate(across(where(is.numeric),~ round(.x, 3))) %>%
  select(!exo) %>% 
  arrange(desc(est)) %>% 
  kbl_rise()
lhs op rhs est se z pvalue
Ledarskap ~~ PsykTrygg 0.489 0.027 18.059 0.000
Återhämtning ~~ Ledarskap 0.384 0.029 13.065 0.000
KränkandeB ~~ PsykTrygg 0.376 0.033 11.264 0.000
Återhämtning ~~ PsykTrygg 0.366 0.030 12.398 0.000
Stöd ~~ PsykTrygg 0.236 0.023 10.467 0.000
Stöd ~~ Ledarskap 0.235 0.021 11.050 0.000
Ledarskap ~~ KränkandeB 0.219 0.034 6.457 0.000
Stöd ~~ Återhämtning 0.188 0.019 9.672 0.000
Återhämtning ~~ KränkandeB 0.187 0.031 6.081 0.000
BelastKrav ~~ Återhämtning 0.164 0.026 6.398 0.000
MöjlPåverka ~~ Återhämtning 0.159 0.023 6.915 0.000
BelastKrav ~~ Ledarskap 0.148 0.024 6.276 0.000
MöjlPåverka ~~ PsykTrygg 0.146 0.024 6.014 0.000
MöjlPåverka ~~ Ledarskap 0.135 0.026 5.247 0.000
Stöd ~~ KränkandeB 0.125 0.018 6.888 0.000
BelastKrav ~~ PsykTrygg 0.124 0.021 5.938 0.000
MöjlPåverka ~~ Stöd 0.079 0.014 5.698 0.000
BelastKrav ~~ Stöd 0.077 0.014 5.624 0.000
BelastKrav ~~ KränkandeB 0.058 0.013 4.418 0.000
BelastKrav ~~ MöjlPåverka 0.051 0.011 4.421 0.000
MöjlPåverka ~~ KränkandeB 0.023 0.020 1.145 0.252

11.2.3 Model plot

Code
lavaanPlot(model = CFArasch, 
           coefs = T, stand = T, covs = T,
           node_options = list(fontname = "Helvetica"), 
           edge_options = list(color = "grey"),
           graph_options = list(rankdir = "LR"))

11.2.4 Modification indices

Ordnade efter storlek, störst först.

itemnr item
ao1 Jag vet vilka arbetsuppgifter jag har.
ao2 Jag vet hur mitt arbete ska utföras.
ao3 Jag vet vilka resultat som jag ska uppnå med mitt arbete.
ao4 Det finns tydliga mål för min arbetsgrupp.
ao5 Det finns tydliga mål för min organisation.
abk1 Min arbetsbelastning är rimlig.
abk2 Jag hinner med mina arbetsuppgifter inom min arbetstid.
abk3 Mitt arbete är lagom omväxlande.
abk4 Jag upplever att andras krav på mig är rimliga.
abk5 Jag kan få hjälp om min arbetsbelastning är för hög.
abk6 Mitt arbete är fritt från psykiskt påfrestande arbetsuppgifter.
mp1 Jag har de resurser som behövs för att kunna utföra mina arbetsuppgifter.
mp2 Jag kan prioritera i vilken ordning mina arbetsuppgifter ska utföras.
mp3 Jag har tillräckligt med befogenheter för att kunna utföra mina arbetsuppgifter.
mp4 Jag kan påverka beslut som rör mina arbetsuppgifter.
mp5 Jag kan själv bestämma min arbetstakt.
st1 Jag vet vem jag ska vända mig till för att få stöd och hjälp med att utföra arbetet.
st2 Det finns personer på mitt arbete som jag kan prata förtroligt med.
st3 Vi samarbetar bra på min arbetsplats.
st4 Jag visar uppskattning till mina kollegor för deras arbetsinsatser.
st5 Mina kollegor visar uppskattning för mina arbetsinsatser.
st6 Jag får tekniskt stöd vid behov.
st7 Jag kan få handledning i mitt arbete om jag behöver det.
å1 Jag kan använda raster till att koppla av från arbetet.
å2 Jag har möjlighet att arbeta i lugnare takt efter arbetsintensiva perioder.
å3 Jag har tid för reflektion över hur jag har utfört arbetet.
å4 Jag har ork kvar för att göra andra saker efter arbetsdagens slut.
å5 Jag kan lägga tankar på arbetet åt sidan på min lediga tid.
ls1 Min chef ger mig återkoppling på hur jag utför arbetet.
ls2 Min chef har en god uppfattning om min arbetsbelastning.
ls3 Min chef agerar om jag har allt för mycket arbete att utföra.
ls4 Min chef ser till att alla kommer till tals.
ls5 Min chef hanterar konflikter på ett bra sätt.
ls6 Min chef och jag har tillräckligt med avstämningar.
ku1 Mina kunskaper och färdigheter är till nytta i mitt arbete.
ku2 Jag har tillräckligt med kunskap/färdigheter för att kunna utföra mina arbetsuppgifter.
ku3 Jag har möjlighet att lära mig nya saker när arbetsuppgifterna kräver det.
ku4 Jag har möjlighet till långsiktig kompetensutveckling i mitt arbete.
kb1 Blivit utsatt för att någon undanhåller information som har påverkat din prestation.
kb2 Blivit utsatt för skvaller eller rykten spridda om dig.
kb3 Blivit ignorerad eller exkluderad.
kb4 Fått kränkande eller stötande kommentarer om dig som person, dina attityder eller ditt privatliv.
kb5 Blivit utskälld eller varit föremål för andras aggressiva utbrott.
kb6 Blivit påmind om dina felsteg eller misstag.
kb7 Blivit utsatt för ett otrevligt bemötande när du närmar dig andra.
pt1 Jag har en positiv känsla när jag kommer till jobbet.
pt2 Jag känner mig delaktig i gemenskapen på min arbetsplats.
pt3 Jag kan begå misstag utan att det hålls emot mig.
pt4 Jag kan öppet diskutera olika typer av svårigheter.
pt5 Jag blir inkluderad även om jag tycker annorlunda.
pt6 Mina ansträngningar värdesätts.
pt7 Mina idéer ges tid och uppmärksamhet.

11.2.4.1 Korsladdningar

Med MI > 50.

Code
modificationIndices(CFArasch,
                    standardized = T) %>% 
  as.data.frame(row.names = NULL) %>% 
  filter(mi > 50,
         op == "=~") %>% 
  arrange(desc(mi)) %>% 
  mutate(across(where(is.numeric),~ round(.x, 3))) %>%
  kbl_rise(fontsize = 14, width = 75)
lhs op rhs mi epc sepc.lv sepc.all sepc.nox
PsykTrygg =~ st5 51.313 0.627 0.52 0.52 0.52

11.2.4.2 Residualkorrelationer

Code
modificationIndices(CFArasch,
                    standardized = T) %>% 
  as.data.frame(row.names = NULL) %>% 
  filter(mi > 20,
         op == "~~") %>% 
  arrange(desc(mi)) %>% 
  mutate(across(where(is.numeric),~ round(.x, 3))) %>%
  kbl_rise(fontsize = 14, width = 75)
lhs op rhs mi epc sepc.lv sepc.all sepc.nox
st1 ~~ st2 42.406 0.243 0.243 0.293 0.293
st5 ~~ pt6 39.028 0.209 0.209 0.542 0.542
abk5 ~~ st7 35.842 0.210 0.210 0.461 0.461
abk5 ~~ ls3 33.206 0.179 0.179 0.540 0.540
pt3 ~~ pt4 21.822 0.123 0.123 0.413 0.413
kb5 ~~ kb6 20.153 0.189 0.189 0.428 0.428