3  Psykiska besvär

Published

August 14, 2025

3.1 Omkodning

Code
### Tar bort observationer som inte är tjej eller kille
df <- df %>%
  filter(!grepl("annan könsidentitet|vill inte svara", tolower(q3)))

df <- df %>% 
  filter(!is.na(q3))

### Byter namn på demografiska variabler
count (df, q3)
# A tibble: 2 × 2
  q3        n
  <chr> <int>
1 Kille   671
2 Tjej    719
Code
count (df, q1)
# A tibble: 2 × 2
  q1                          n
  <chr>                   <int>
1 År 2 på gymnasiet         744
2 Årskurs 9 i grundskolan   646
Code
count (df, q6)
# A tibble: 5 × 2
  q6                      n
  <chr>               <int>
1 Annat boende           19
2 Bostadsrätt           333
3 Hyreslägenhet         266
4 Villa/parhus/radhus   767
5 <NA>                    5
Code
d <- df %>% 
  rename(Kön = q3) %>% 
  rename(Årskurs = q1) %>%
  rename(Bostad = q6) 

count (d, Kön)
# A tibble: 2 × 2
  Kön       n
  <chr> <int>
1 Kille   671
2 Tjej    719
Code
count (df, q7, q8, q9)
# A tibble: 53 × 4
   q7        q8                         q9                              n
   <chr>     <chr>                      <chr>                       <int>
 1 I Sverige I Sverige                  I Sverige                     863
 2 I Sverige I Sverige                  I ett land i övriga Europa     37
 3 I Sverige I Sverige                  I ett land i övriga Norden     16
 4 I Sverige I Sverige                  I ett land i övriga världen    77
 5 I Sverige I Sverige                  <NA>                            1
 6 I Sverige I ett land i övriga Europa I Sverige                      29
 7 I Sverige I ett land i övriga Europa I ett land i övriga Europa     28
 8 I Sverige I ett land i övriga Europa I ett land i övriga världen     6
 9 I Sverige I ett land i övriga Norden I Sverige                      13
10 I Sverige I ett land i övriga Norden I ett land i övriga Europa      3
# ℹ 43 more rows
Code
### Koda om kön till numerisk + rätt etiketter

#d$Kön <- recode(d$Kön,"'Tjej'=1;'Kille'=2",as.factor=FALSE)
#d$Kön <- labelled(d$Kön, labels = c("Tjej" = 1, "Kille" = 2))

#d$Årskurs<-recode(d$Årskurs,"'Årskurs 9 i grundskolan'=1;'År 2 på gymnasiet'=2",as.factor=FALSE)
#d$Årskurs <- labelled(d$Årskurs, labels = c("årskurs 9" = 1, "år 2" = 2))

d$Kön <- factor(d$Kön)
d$Årskurs <- factor(d$Årskurs, labels = c("Åk 9","Gy 2"))

3.2 Välbefinnande

Code
count (df, q13, q20)
# A tibble: 29 × 3
   q13         q20               n
   <chr>       <chr>         <int>
 1 Aldrig      Lika bra          1
 2 Aldrig      Lite bättre       2
 3 Aldrig      Lite sämre        5
 4 Aldrig      Mycket bättre     5
 5 Aldrig      Mycket sämre      8
 6 Ganska ofta Lika bra        203
 7 Ganska ofta Lite bättre     161
 8 Ganska ofta Lite sämre       66
 9 Ganska ofta Mycket bättre   114
10 Ganska ofta Mycket sämre     12
# ℹ 19 more rows
Code
välbefinnande <- c("q13", "q14", "q15", "q16", "q17", "q18", "q19", "q20")


 # Koda om till numeriska + etiktter. Låga värden = lågt välbefinnande
d <- d %>%
  mutate(across(q13:q17, ~ recode(.x,
                                  "'Mycket ofta'=4; 'Ganska ofta'=3; 'Ibland'=2; 'Sällan'=1; 'Aldrig'=0", 
                                  as.factor = FALSE))) %>%
  mutate(across(q13:q17, ~ labelled(.x,
                                    labels = c("Mycket ofta" = 4,
                                               "Ganska ofta" = 3,
                                               "Ibland" = 2,
                                               "Sällan" = 1,
                                               "Aldrig" = 0))))

d <- d %>%
  mutate(across(q18:q19, ~ recode(.x,
                                  "'Alltid'=5; 'Mycket ofta'=4; 'Ganska ofta'=3; 'Ibland'=2; 'Sällan'=1; 'Aldrig'=0", 
                                  as.factor = FALSE))) %>%
  mutate(across(q18:q19, ~ labelled(.x,
                                    labels = c("Alltid" = 5,
                                               "Mycket ofta" = 4,
                                               "Ganska ofta" = 3,
                                               "Ibland" = 2,
                                               "Sällan" = 1,
                                               "Aldrig" = 0))))

d$q20<-recode(d$q20,"'Mycket bättre'=4;'Lite bättre'=3; 'Lika bra'=2; 'Lite sämre'=1; 'Mycket sämre'=0",as.factor=FALSE)
d$q20 <- labelled(d$q20, labels = c("Mycket bättre" = 4, "Lite bättre" = 3, "Lika bra" = 2, "Lite sämre" = 1,"Mycket sämre" = 0))


count (d, q13)
# A tibble: 6 × 2
  q13                  n
  <dbl+lbl>        <int>
1  0 [Aldrig]         21
2  1 [Sällan]         59
3  2 [Ibland]        237
4  3 [Ganska ofta]   556
5  4 [Mycket ofta]   514
6 NA                   3
Code
count (d, q14)
# A tibble: 6 × 2
  q14                  n
  <dbl+lbl>        <int>
1  0 [Aldrig]         26
2  1 [Sällan]         71
3  2 [Ibland]        211
4  3 [Ganska ofta]   483
5  4 [Mycket ofta]   593
6 NA                   6
Code
count (d, q15)
# A tibble: 6 × 2
  q15                  n
  <dbl+lbl>        <int>
1  0 [Aldrig]         36
2  1 [Sällan]         90
3  2 [Ibland]        298
4  3 [Ganska ofta]   521
5  4 [Mycket ofta]   439
6 NA                   6
Code
count (d, q16)
# A tibble: 6 × 2
  q16                  n
  <dbl+lbl>        <int>
1  0 [Aldrig]         74
2  1 [Sällan]        252
3  2 [Ibland]        429
4  3 [Ganska ofta]   396
5  4 [Mycket ofta]   234
6 NA                   5
Code
count (d, q17)
# A tibble: 6 × 2
  q17                  n
  <dbl+lbl>        <int>
1  0 [Aldrig]         53
2  1 [Sällan]        195
3  2 [Ibland]        419
4  3 [Ganska ofta]   454
5  4 [Mycket ofta]   264
6 NA                   5
Code
count (d, q18)
# A tibble: 6 × 2
  q18                 n
  <dbl+lbl>       <int>
1 0 [Aldrig]         14
2 1 [Sällan]         49
3 2 [Ibland]        196
4 3 [Ganska ofta]   446
5 4 [Mycket ofta]   528
6 5 [Alltid]        157
Code
count (d, q19)
# A tibble: 7 × 2
  q19                  n
  <dbl+lbl>        <int>
1  0 [Aldrig]         46
2  1 [Sällan]        125
3  2 [Ibland]        271
4  3 [Ganska ofta]   415
5  4 [Mycket ofta]   314
6  5 [Alltid]        210
7 NA                   9
Code
count (d, q20)
# A tibble: 6 × 2
  q20                    n
  <dbl+lbl>          <int>
1  0 [Mycket sämre]     42
2  1 [Lite sämre]      154
3  2 [Lika bra]        465
4  3 [Lite bättre]     420
5  4 [Mycket bättre]   307
6 NA                     2

3.3 PSF

Code
count (df, q21, q28)
# A tibble: 25 × 3
   q21           q28                           n
   <chr>         <chr>                     <int>
 1 Aldrig/sällan En eller två dagar          262
 2 Aldrig/sällan Flera dagar                 112
 3 Aldrig/sällan Inte besvärats alls         470
 4 Aldrig/sällan Mer än hälften av dagarna    32
 5 Aldrig/sällan Nästan varje dag             25
 6 Aldrig/sällan <NA>                          2
 7 Ganska ofta   En eller två dagar           30
 8 Ganska ofta   Flera dagar                  29
 9 Ganska ofta   Inte besvärats alls           7
10 Ganska ofta   Mer än hälften av dagarna    10
# ℹ 15 more rows
Code
psf <- c("q21", "q22", "q23", "q24", "q25", "q26", "q27", "q28")


 # Koda om till numeriska + etiktter. Låga värden = låg risk
d <- d %>%
  mutate(across(q21:q24, ~ recode(.x,
                                  "'Aldrig/sällan'=0; 'Ibland'=1; 'Ganska ofta'=2; 'Mycket ofta'=3", 
                                  as.factor = FALSE))) %>%
  mutate(across(q21:q24, ~ labelled(.x,
                                    labels = c("Aldrig/sällan" = 0,
                                               "Ibland" = 1,
                                               "Ganska ofta" = 2,
                                               "Mycket ofta" = 3))))

d <- d %>%
  mutate(across(q25:q28, ~ recode(.x,
                                  "'Inte besvärats alls'=0; 'En eller två dagar'=1; 'Flera dagar'=2; 'Mer än hälften av dagarna'=3; 'Nästan varje dag'=4", 
                                  as.factor = FALSE))) %>%
  mutate(across(q25:q28, ~ labelled(.x,
                                    labels = c("Inte besvärats alls" = 0,
                                               "En eller två dagar" = 1,
                                               "Flera dagar" = 2,
                                               "Mer än hälften av dagarna" = 3, "Nästan varje dag" = 4))))

#d$q20<-recode(d$q20,"'Mycket bättre'=0;'Lite bättre'=1; 'Lika bra'=2; 'Lite sämre'=3; 'Mycket sämre'=4",as.factor=FALSE)
#d$q20 <- labelled(d$q20, labels = c("Mycket bättre" = 0, "Lite bättre" = 1, "Lika bra" = 2, "Lite sämre" = 3,"Mycket sämre" = 4))


count (d, q21)
# A tibble: 5 × 2
  q21                    n
  <dbl+lbl>          <int>
1  0 [Aldrig/sällan]   903
2  1 [Ibland]          361
3  2 [Ganska ofta]      86
4  3 [Mycket ofta]      34
5 NA                     6
Code
count (d, q28)
# A tibble: 6 × 2
  q28                                n
  <dbl+lbl>                      <int>
1  0 [Inte besvärats alls]         564
2  1 [En eller två dagar]          440
3  2 [Flera dagar]                 223
4  3 [Mer än hälften av dagarna]    80
5  4 [Nästan varje dag]             75
6 NA                                 8

3.4 Våld

Code
våld_utsatt <- c("q21", "q22", "q23", "q24", "q25", "q26", "q27", "q28")

våld_förövare <- c("q21", "q22", "q23", "q24", "q25", "q26", "q27", "q28")

#våld_följd
Code
#d %>% 
  #select(q13:q20) %>% 
  #pivot_longer(everything()) %>% 
  #distinct(value)

Sektionen i PDF/pappers-enkäten inleds med meningen: “NÅGRA FRÅGOR OM HUR DU MÅR”.

3.5 DF för välbefinnande

Code
# Skapa dataframe för välbefinnande utan NA:s
d_v <- d %>% 
  select(Kön, Årskurs, Bostad, any_of(välbefinnande))%>% 
  na.omit()

# Skapa DIF df
d_dif_v <- d_v %>% 
  select(Kön, Årskurs, Bostad) %>% 
  mutate(across(everything(), ~ factor(.x)))

# remove non-items
d_v <- d_v %>% 
  select(!c(Kön,Årskurs,Bostad))

3.6 DF för PSF

Code
# Skapa dataframe för alla PSF utan NA:s
d_psf <- d %>% 
  select(Kön, Årskurs, Bostad, any_of(psf))%>% 
  na.omit()

# Skapa DIF df
d_dif__psf <- d_psf %>% 
  select(Kön, Årskurs, Bostad) %>% 
  mutate(across(everything(), ~ factor(.x)))

# remove non-items
d_psf <- d_psf %>% 
  select(!c(Kön,Årskurs,Bostad))


# Skapa dataframe för depressionsitems utan NA:s
d_psf_d <- d %>% 
  select(Kön, Årskurs, Bostad, any_of(c("q22", "q23", "q24", "q27", "q28")))%>% 
  na.omit()

# Skapa DIF df
d_dif__psf_d <- d_psf_d %>% 
  select(Kön, Årskurs, Bostad) %>% 
  mutate(across(everything(), ~ factor(.x)))

# remove non-items
d_psf_d <- d_psf_d %>% 
  select(!c(Kön,Årskurs,Bostad))

# Skapa dataframe för ångestitems utan NA:s
d_psf_å <- d %>% 
  select(Kön, Årskurs, Bostad, any_of(c("q21", "q25", "q26")))%>% 
  na.omit()

# Skapa DIF df
d_dif__psf_å <- d_psf_å %>% 
  select(Kön, Årskurs, Bostad) %>% 
  mutate(across(everything(), ~ factor(.x)))

# remove non-items
d_psf_å <- d_psf_å %>% 
  select(!c(Kön,Årskurs,Bostad))

3.7 Färger

Code
RISEpalette1 <- colorRampPalette(colors = c("#009ca6", "#e83c63", "#ffe500"))(6)
#scales::show_col(RISEpalette1)

RISEpalette2 <- colorRampPalette(colors = c("#009ca6", "#482d55", "#e83c63", "#ffe500"))(8)

gender_colors <- c("Kille" = colorspace::lighten("#F5A127", amount = 0.2) , "Tjej" = colorspace::lighten("#009CA6", amount = 0.2))
scale_color_gender <- partial(scale_color_manual, values = gender_colors)
scale_fill_gender <- partial(scale_fill_manual, values = gender_colors)

##Välbefinnande
labels_v_13_17 <-c(
                                               "Mycket ofta" = 0,
                                               "Ganska ofta" = 1,
                                               "Ibland" = 2,
                                               "Sällan" = 3, "Aldrig" = 4)
names(labels_v_13_17)
[1] "Mycket ofta" "Ganska ofta" "Ibland"      "Sällan"      "Aldrig"     
Code
labels_v_18_19 <-c("Alltid" = 0,
                                               "Mycket ofta" = 1,
                                               "Ganska ofta" = 2,
                                               "Ibland" = 3,
                                               "Sällan" = 4, "Aldrig" = 5)
names(labels_v_18_19)
[1] "Alltid"      "Mycket ofta" "Ganska ofta" "Ibland"      "Sällan"     
[6] "Aldrig"     
Code
labels_v_20 <-c("Mycket bättre" = 0,
                                               "Lite bättre" = 1,
                                               "Lika bra" = 2,
                                               "Lite bättre" = 3,
                                               "Mycket bättre" = 3)
names(labels_v_20)
[1] "Mycket bättre" "Lite bättre"   "Lika bra"      "Lite bättre"  
[5] "Mycket bättre"
Code
##PSF
labels_p_21_24 <-c("Aldrig/sällan" = 0,
                                               "Ibland" = 1,
                                               "Ganska ofta" = 2,
                                               "Mycket ofta" = 3)
names(labels_p_21_24)
[1] "Aldrig/sällan" "Ibland"        "Ganska ofta"   "Mycket ofta"  
Code
labels_p_25_28 <-c("Inte besvärats alls" = 0,
                                               "En eller två dagar" = 1,
                                               "Flera dagar" = 2,
                                               "Mer än hälften av dagarna" = 3, "Nästan varje dag" = 4)
names(labels_p_25_28)
[1] "Inte besvärats alls"       "En eller två dagar"       
[3] "Flera dagar"               "Mer än hälften av dagarna"
[5] "Nästan varje dag"         

3.8 Deskriptiva data Välbefinnande

3.9 Formatering figur

Code
plot_gender <- function(data, items, kolumner = 2, labelwrap = 24, text_ypos = 28, text_size = 3) {
  
  data %>% 
    pivot_longer(all_of(items),
                 names_to = "itemnr") %>% 
    group_by(itemnr,Kön) %>% 
    count(value) %>% 
    mutate(percent = n*100/sum(n)) %>% 
    ungroup() %>% 
    mutate(Kön = factor(Kön, labels = c("Tjej","Kille")),
           value = factor(value, ordered = T)) %>% 
    left_join(itemlabels, by = "itemnr") %>%
    
    ggplot(aes(x = value, y = n, fill = Kön)) +
    geom_col(position = "dodge") +
    geom_text(aes(label = paste0(round(percent,1),"%"), 
                  y = text_ypos),
              position = position_dodge(width = 0.9),
              angle = 0,
              color = "black",
              size = text_size,
              hjust = "left") +
    facet_wrap(~item, 
               ncol = kolumner,
               labeller = labeller(item = label_wrap_gen(labelwrap))) +
    scale_fill_gender() +
    theme_rise(fontfamily = "Avenir") +
    labs(x = "Svarskategori",
         y = "Antal svar",
         caption = "Andel svar anges i procent i figuren.") +
    coord_flip()
}

3.10 Deskriptiva figurer blivit välbefinnande

Code
## Utfryst, rykte, trakasserad, begränsad
d %>% 
  plot_gender(items = c("q13", "q14", "q15", "q16", "q17"), labelwrap = 32, text_ypos = 20) +
  scale_x_discrete(labels = str_wrap(names(labels_v_13_17), 14))

Code
d %>% 
  plot_gender(items = c("q18", "q19"), labelwrap = 32, text_ypos = 20) +
  scale_x_discrete(labels = str_wrap(names(labels_v_18_19), 14))

Code
d %>% 
  plot_gender(items = c("q20"), labelwrap = 32, text_ypos = 20) +
  scale_x_discrete(labels = str_wrap(names(labels_v_20), 14))

3.11 Deskriptiva figurer PSF

Code
## Utfryst, rykte, trakasserad, begränsad
d %>% 
  plot_gender(items = c("q21", "q22", "q23", "q24"), labelwrap = 32, text_ypos = 20) +
  scale_x_discrete(labels = str_wrap(names(labels_p_21_24), 14))

Code
d %>% 
  plot_gender(items = c("q25", "q26", "q27", "q28"), labelwrap = 32, text_ypos = 20) +
  scale_x_discrete(labels = str_wrap(names(labels_p_25_28), 14))

3.11.1 Demografi

3.11.2 Item-data

Code
RItileplot(d_psf)

Code
RIbarstack(d_psf)

Code
RIbarplot(d_psf)

3.12 Analys 1 samtliga items PSF

itemnr item
q21 du känner dig rädd utan att veta varför?
q22 du känner att du inte duger?
q23 du känner dig slö och olustig?
q24 du känner dig ledsen eller deppig utan att veta varför?
q25 Känt dig nervös, orolig eller spänd
q26 Haft svårt att sluta oroa dig eller kontrollera din oro
q27 Minskat intresse eller glädje att göra saker
q28 Känt dig nedstämd eller upplevt en känsla av hopplöshet
Code
aisp(d_psf) %>% 
  as.data.frame() %>% 
  set_names("h > 0.3") %>% 
  arrange(`h > 0.3`) %>% 
  kbl_rise(tbl_width = 20)
h > 0.3
q21 1
q22 1
q23 1
q24 1
q25 1
q26 1
q27 1
q28 1
Code
d_psf %>% 
  RIbootRestscore(iterations = 250, samplesize = 600, cpu = 8)
Item Item-restscore result % of iterations Conditional MSQ infit Relative average item location
q21 underfit 30.0 1.19 2.39
q23 underfit 17.6 1.10 1.12
q27 underfit 12.0 1.14 1.44
q28 overfit 96.8 0.80 1.42
q26 overfit 89.2 0.80 1.26
q24 overfit 31.6 0.90 1.32
Note:
Results based on 250 bootstrap iterations with n = 600 and 8 items. Conditional mean-square infit based on complete responders only (n = 1365).
Code
RIpcmPCA(d_psf)

PCA of Rasch model residuals

Eigenvalues Proportion of variance
1.82 22.3%
1.51 19.9%
1.15 15.4%
1.03 13.9%
0.92 11.8%
Code
RIloadLoc(d_psf)

Code
RIbootLRT(d_psf, cpu = 8, samplesize = 400)
Result n Percent
Not statistically significant 1000 100
Code
RIpartgamLD(d_psf)
Item 1 Item 2 Partial gamma SE Lower CI Upper CI Adjusted p-value (BH)
q26 q25 0.612 0.034 0.546 0.678 0.000
q25 q26 0.555 0.036 0.485 0.625 0.000
q28 q27 0.437 0.043 0.354 0.521 0.000
q24 q21 0.335 0.055 0.228 0.442 0.000
q27 q28 0.314 0.047 0.223 0.406 0.000
q24 q22 0.261 0.053 0.157 0.365 0.000
q28 q24 0.244 0.053 0.141 0.348 0.000
q21 q24 0.239 0.056 0.130 0.349 0.001
q22 q24 0.223 0.054 0.117 0.328 0.002
q24 q28 0.217 0.053 0.113 0.321 0.002
q22 q23 0.205 0.052 0.103 0.308 0.005
q23 q22 0.187 0.052 0.084 0.289 0.020
Code
simcor <- RIgetResidCor(d_psf, iterations = 1000, cpu = 8)
RIresidcorr(d_psf, simcor$p999)
q21 q22 q23 q24 q25 q26 q27 q28
q21
q22 0.01
q23 -0.03 0.03
q24 0.05 0.02 -0.01
q25 -0.18 -0.24 -0.21 -0.36
q26 -0.09 -0.23 -0.31 -0.26 0.29
q27 -0.29 -0.25 -0.12 -0.15 -0.2 -0.22
q28 -0.28 -0.15 -0.21 -0.01 -0.21 -0.14 0.12
Note:
Relative cut-off value is 0.008, which is 0.138 above the average correlation (-0.13).
Correlations above the cut-off are highlighted in red text.
Code
RItargeting(d_psf)

Code
RIitemHierarchy(d_psf)

Code
mirt(d_psf, model=1, itemtype='Rasch', verbose = FALSE) %>% 
  plot(type="trace", as.table = TRUE, 
       theta_lim = c(-4,7))

Code
RIpfit(d_psf)

Code
RIpartgamDIF(d_psf, d_dif__psf$Kön)
Item Partial gamma SE Lower CI Upper CI Adjusted p-value (BH)
q24 0.333 0.060 0.216 0.450 0
q27 -0.28 0.057 -0.392 -0.169 0
Code
RIdifTableLR(d_psf, d_dif__psf$Kön)
Item locations
Standard errors
Item Kille Tjej MaxDiff All SE_Kille SE_Tjej SE_All
q21 1.456 1.658 0.202 1.590 0.286 0.174 0.147
q22 0.445 0.658 0.213 0.619 0.179 0.131 0.103
q23 0.116 0.441 0.325 0.320 0.165 0.133 0.102
q24 0.627 0.392 0.235 0.520 0.192 0.127 0.101
q25 -0.435 -0.411 0.024 -0.440 0.179 0.140 0.105
q26 0.561 0.413 0.148 0.459 0.219 0.137 0.112
q27 0.287 0.834 0.547 0.636 0.201 0.153 0.120
q28 0.584 0.651 0.067 0.625 0.226 0.146 0.120
Note:
Values highlighted in red are above the chosen cutoff 0.5 logits. Background color brown and blue indicate the lowest and highest values among the DIF groups.
Code
RIdifThreshFigLR(d_psf, d_dif__psf$Kön)

Code
#RIciccPlot(d_rest, dif = "yes", dif_var = d_dif_rest$kon)
Code
RIpartgamDIF(d_psf, d_dif__psf$Årskurs)
[1] "No statistically significant DIF found."
Code
RIdifTableLR(d_psf, d_dif__psf$Årskurs)
Item locations
Standard errors
Item Åk 9 Gy 2 MaxDiff All SE_Åk 9 SE_Gy 2 SE_All
q21 1.733 1.422 0.311 1.590 0.200 0.226 0.147
q22 0.629 0.603 0.026 0.619 0.137 0.157 0.103
q23 0.299 0.337 0.038 0.320 0.136 0.156 0.102
q24 0.614 0.408 0.206 0.520 0.138 0.149 0.101
q25 -0.425 -0.452 0.027 -0.440 0.142 0.156 0.105
q26 0.424 0.511 0.087 0.459 0.150 0.173 0.112
q27 0.749 0.503 0.246 0.636 0.165 0.177 0.120
q28 0.667 0.575 0.092 0.625 0.159 0.183 0.120
Note:
Values highlighted in red are above the chosen cutoff 0.5 logits. Background color brown and blue indicate the lowest and highest values among the DIF groups.
Code
RIdifThreshFigLR(d_psf, d_dif__psf$Årskurs)

Code
#RIciccPlot(d_rest, dif = "yes", dif_var = d_dif_rest$arskurs)
Code
RIpartgamDIF(d_v, d_dif_v$Bostad)
Item Partial gamma SE Lower CI Upper CI Adjusted p-value (BH)
q15 0.144 0.052 0.042 0.247 0.045
q16 -0.125 0.045 -0.212 -0.037 0.043
Code
#RIdifTableLR(d_v, d_dif_v$Bostad)
#RIdifThreshFigLR(d_v, d_dif_v$Bostad)
#RIciccPlot(d_rest, dif = "yes", dif_var = d_dif_rest$year)
  • Alla frågor 1 i Mokken
  • Ingen underfit, alla items verkar höra till samma/närliggande konstrukt
  • Overfit på q28 och q26 - dessa är “core items” för depression respektive ångest i PHQ och GAD-enkäterna
  • PCA 1.82
  • Lokalt beroende främst mellan q26 “oro” och q25 “nervös, orolig, spänd”, samt q27 “minskat intresse” och q28 “nedstämd och hopplöst”
    • dessa par är PHQ-2 (depression) och GAD-2 (oro/ångest), så de förväntas vara lika varandra, och minst en publicerad artikel har identifierat PHQ-items som för lika varandra när de används i PHQ-9, d.v.s. i kontexten av items som mäter något bredare än bara depression.
  • Targeting ok förutom ganska ycket golveffekter dvs. vi kan inte mäta så bra där det förekommer lägre värden av psykisk ohälsa, vilket är väntat.
  • Oordnade svarskategorier på q28, q26 och q25, i samtliga fall gällande de två översta kategorierna
  • De understa svarskategorierna fungerar utmärkt, vilket är viktigt för 25-28 där vi la till en svarskategori, vilket har gett goda resultat.

3.13 Eliminering av item

Även om det inte är det primära syftet är det intressant att se om det går att hitta en uppsättning items som fungerar tillsammans.

Code
d_psf %>% 
  select(!c(q25,q27)) %>% 
  RIbootRestscore(iterations = 250,samplesize = 600, cpu = 8)
Item Item-restscore result % of iterations Conditional MSQ infit Relative average item location
q23 underfit 26.0 1.13 1.08
q24 overfit 77.2 0.84 1.30
q28 overfit 22.4 0.94 1.42
Note:
Results based on 250 bootstrap iterations with n = 600 and 6 items. Conditional mean-square infit based on complete responders only (n = 1365).
Code
d_psf %>% 
  select(!c(q25,q27)) %>% 
  RIbootLRT(cpu = 8, samplesize = 400)
Result n Percent
Not statistically significant 358 35.8
Statistically significant 642 64.2
Code
simcor2527 <- d_psf %>% 
  select(!c(q25,q27)) %>% 
  RIgetResidCor(iterations = 500, cpu = 8)
d_psf %>% 
  select(!c(q25,q27)) %>% 
  RIresidcorr(simcor2527$p999)
q21 q22 q23 q24 q26 q28
q21
q22 -0.11
q23 -0.12 -0.07
q24 -0.07 -0.12 -0.12
q26 -0.14 -0.28 -0.31 -0.31
q28 -0.36 -0.23 -0.25 -0.08 -0.06
Note:
Relative cut-off value is -0.035, which is 0.143 above the average correlation (-0.177).
Correlations above the cut-off are highlighted in red text.
Code
d_psf %>% 
  select(!c(q25,q27)) %>% 
  RItargeting()

Code
d_psf %>% 
  select(!c(q25,q27)) %>% 
  mutate(across(c(q26,q28), ~ recode(.x,"4=3"))) %>% 
  RItargeting()

Ser ganska bra ut. Item 24 möjligen overfit, men inga residualkorrelationer, så det bör inte vara problematiskt. Översta svarskategorierna för 26 och 28 fortfarande oordnade.

Code
d_psf %>% 
  select(!c(q26,q28)) %>% 
  RIbootRestscore(iterations = 250, samplesize = 600,cpu = 8)
Item Item-restscore result % of iterations Conditional MSQ infit Relative average item location
q25 underfit 20.4 1.16 0.32
q27 underfit 8.0 1.15 1.31
q24 overfit 80.0 0.83 1.22
q22 overfit 35.2 0.89 1.31
q23 overfit 6.0 0.95 1.04
Note:
Results based on 250 bootstrap iterations with n = 600 and 6 items. Conditional mean-square infit based on complete responders only (n = 1365).
Code
d_psf %>% 
  select(!c(q26,q28)) %>% 
  RIbootLRT(cpu = 8, samplesize = 400)
Result n Percent
Not statistically significant 927 92.7
Statistically significant 73 7.3
Code
simcor2527 <- d_psf %>% 
  select(!c(q26,q28)) %>% 
  RIgetResidCor(iterations = 500, cpu = 8)

d_psf %>% 
  select(!c(q26,q28)) %>% 
  RIresidcorr(simcor2527$p999)
q21 q22 q23 q24 q25 q27
q21
q22 -0.06
q23 -0.11 -0.07
q24 -0.01 -0.03 -0.09
q25 -0.19 -0.25 -0.24 -0.33
q27 -0.34 -0.29 -0.19 -0.16 -0.15
Note:
Relative cut-off value is -0.022, which is 0.144 above the average correlation (-0.166).
Correlations above the cut-off are highlighted in red text.
Code
d_psf %>% 
  select(!c(q26,q28)) %>% 
  RItargeting()

Code
d_psf %>% 
  select(!c(q26,q28)) %>% 
  mutate(across(c(q25,q27), ~ recode(.x,"4=3"))) %>% 
  RItargeting()

Liknande resultat, men 24 involverad i borderline residualkorrelation med 21. Lite bättre targeting än när 25 och 27 tas bort.

Code
d_psf %>% 
  select(!c(q25,q27,q24)) %>% 
  RIbootRestscore(iterations = 250, samplesize = 600, cpu = 8)
Item Item-restscore result % of iterations Conditional MSQ infit Relative average item location
q23 underfit 8.4 1.10 1.03
q28 overfit 15.2 0.94 1.34
Note:
Results based on 250 bootstrap iterations with n = 600 and 5 items. Conditional mean-square infit based on complete responders only (n = 1365).
Code
d_psf %>% 
  select(!c(q25,q27,q24)) %>% 
  RIbootLRT(cpu = 8, samplesize = 400)
Result n Percent
Not statistically significant 706 70.6
Statistically significant 294 29.4
Code
simcor252724 <- d_psf %>% 
  select(!c(q25,q27,q24)) %>% 
  RIgetResidCor(iterations = 500, cpu = 8)
d_psf %>% 
  select(!c(q25,q27,q24)) %>% 
  RIresidcorr(simcor252724$p999)
q21 q22 q23 q26 q28
q21
q22 -0.11
q23 -0.12 -0.08
q26 -0.18 -0.34 -0.36
q28 -0.36 -0.23 -0.25 -0.1
Note:
Relative cut-off value is -0.051, which is 0.164 above the average correlation (-0.215).
Correlations above the cut-off are highlighted in red text.

Ser bättre ut utan 24.

Code
d_psf %>% 
  select(!c(q25,q27,q24)) %>% 
  RIlistitems()
itemnr item
q21 du känner dig rädd utan att veta varför?
q22 du känner att du inte duger?
q23 du känner dig slö och olustig?
q26 Haft svårt att sluta oroa dig eller kontrollera din oro
q28 Känt dig nedstämd eller upplevt en känsla av hopplöshet
Code
d_psf %>% 
  select(!c(q25,q27,q24)) %>% 
  RItargeting()

Code
d_psf %>% 
  select(!c(q25,q27,q24)) %>% 
  mutate(across(c(q26,q28), ~ recode(.x,"4=3"))) %>% 
  RItargeting()

Code
d_psf %>% 
  select(!c(q25,q27,q24)) %>% 
  mutate(across(c(q26,q28), ~ recode(.x,"4=3"))) %>% 
  RItif(samplePSI = T, cutoff = 3)

Mest de övre svarskategorierna på item 26 och 28 som vållar problem.

Klar golveffekt, vilket inte är oväntat.

3.14 Analys 2 samtliga items

Vi tar bort 25 och 27 samt slår samman de två översta svarskategorierna för 26 och 28.

Code
d_psf %>% 
  select(!c(q25,q27)) %>% 
  mutate(across(c(q26,q28), ~ recode(.x,"4=3"))) %>% 
  RIitemHierarchy()

Code
d_psf %>% 
  select(!c(q25,q27)) %>% 
  mutate(across(c(q26,q28), ~ recode(.x,"4=3"))) %>%
  
mirt(model=1, itemtype='Rasch', verbose = FALSE) %>% 
  plot(type="trace", as.table = TRUE, 
       theta_lim = c(-4,7))

Code
d_psf %>% 
  select(!c(q25,q27)) %>% 
  mutate(across(c(q26,q28), ~ recode(.x,"4=3"))) %>% 
RIpfit()

Code
d_psf %>% 
  select(!c(q25,q27)) %>% 
  mutate(across(c(q26,q28), ~ recode(.x,"4=3"))) %>% 
  RIpartgamDIF(d_dif__psf$Kön)
Item Partial gamma SE Lower CI Upper CI Adjusted p-value (BH)
q24 0.27 0.065 0.143 0.397 0.000
q23 -0.171 0.064 -0.296 -0.046 0.043
Code
d_psf %>% 
  select(!c(q25,q27)) %>% 
  mutate(across(c(q26,q28), ~ recode(.x,"4=3"))) %>% 
  RIdifTableLR(d_dif__psf$Kön)
Item locations
Standard errors
Item Kille Tjej MaxDiff All SE_Kille SE_Tjej SE_All
q21 1.471 1.648 0.177 1.585 0.291 0.179 0.151
q22 0.331 0.606 0.275 0.539 0.186 0.132 0.105
q23 -0.044 0.383 0.427 0.216 0.172 0.135 0.105
q24 0.541 0.33 0.211 0.433 0.199 0.129 0.104
q26 0.049 -0.094 0.143 -0.058 0.163 0.118 0.093
q28 0.098 0.171 0.073 0.131 0.170 0.120 0.096
Note:
Values highlighted in red are above the chosen cutoff 0.5 logits. Background color brown and blue indicate the lowest and highest values among the DIF groups.
Code
d_psf %>% 
  select(!c(q25,q27)) %>% 
  mutate(across(c(q26,q28), ~ recode(.x,"4=3"))) %>% 
  RIdifThreshFigLR(d_dif__psf$Kön)

Code
d_psf %>% 
  select(!c(q25,q27)) %>% 
  mutate(across(c(q26,q28), ~ recode(.x,"4=3"))) %>% 
  RIciccPlot(dif = "yes", dif_var = d_dif__psf$Kön)

Code
d_psf %>% 
  select(!c(q25,q27)) %>% 
  mutate(across(c(q26,q28), ~ recode(.x,"4=3"))) %>% 
  RIpartgamDIF(d_dif__psf$Årskurs)
[1] "No statistically significant DIF found."
Code
d_psf %>% 
  select(!c(q25,q27)) %>% 
  mutate(across(c(q26,q28), ~ recode(.x,"4=3"))) %>% 
  RIdifTableLR(d_dif__psf$Årskurs)
Item locations
Standard errors
Item Åk 9 Gy 2 MaxDiff All SE_Åk 9 SE_Gy 2 SE_All
q21 1.715 1.431 0.284 1.585 0.205 0.232 0.151
q22 0.558 0.512 0.046 0.539 0.140 0.161 0.105
q23 0.214 0.211 0.003 0.216 0.140 0.161 0.105
q24 0.544 0.297 0.247 0.433 0.141 0.154 0.104
q26 -0.081 -0.037 0.044 -0.058 0.123 0.142 0.093
q28 0.158 0.096 0.062 0.131 0.128 0.145 0.096
Note:
Values highlighted in red are above the chosen cutoff 0.5 logits. Background color brown and blue indicate the lowest and highest values among the DIF groups.
Code
d_psf %>% 
  select(!c(q25,q27)) %>% 
  mutate(across(c(q26,q28), ~ recode(.x,"4=3"))) %>% 
  RIdifThreshFigLR(d_dif__psf$Årskurs)

Code
d_psf %>% 
  select(!c(q25,q27)) %>% 
  mutate(across(c(q26,q28), ~ recode(.x,"4=3"))) %>% 
  RIciccPlot(dif = "yes", dif_var = d_dif__psf$Årskurs)

Code
d_psf %>% 
  select(!c(q25,q27)) %>% 
  mutate(across(c(q26,q28), ~ recode(.x,"4=3"))) %>% 
  RItif(samplePSI = T)

Ser acceptabelt ut.

3.15 Analys 1 - Depression

itemnr item
q22 du känner att du inte duger?
q23 du känner dig slö och olustig?
q24 du känner dig ledsen eller deppig utan att veta varför?
q27 Minskat intresse eller glädje att göra saker
q28 Känt dig nedstämd eller upplevt en känsla av hopplöshet
Code
aisp(d_psf_d) %>% 
  as.data.frame() %>% 
  set_names("h > 0.3") %>% 
  arrange(`h > 0.3`) %>% 
  kbl_rise(tbl_width = 20)
h > 0.3
q22 1
q23 1
q24 1
q27 1
q28 1
Code
d_psf_d %>% 
  RIbootRestscore(iterations = 250, samplesize = 600, cpu = 8)
Item Item-restscore result % of iterations Conditional MSQ infit Relative average item location
q23 underfit 15.2 1.12 1.10
q28 overfit 89.2 0.81 1.42
q24 overfit 28.4 0.89 1.31
Note:
Results based on 250 bootstrap iterations with n = 600 and 5 items. Conditional mean-square infit based on complete responders only (n = 1369).
Code
RIpcmPCA(d_psf_d)

PCA of Rasch model residuals

Eigenvalues Proportion of variance
1.64 34%
1.27 26.6%
1.10 22.1%
0.98 17.1%
0.01 0.1%
Code
RIloadLoc(d_psf_d)

Code
RIbootLRT(d_psf_d, samplesize = 400, cpu = 8)
Result n Percent
Not statistically significant 563 56.3
Statistically significant 437 43.7
Code
simcor <- RIgetResidCor(d_psf_d, iterations = 500, cpu = 8)

RIresidcorr(d_psf_d, cutoff = simcor$p999)
q22 q23 q24 q27 q28
q22
q23 -0.08
q24 -0.09 -0.13
q27 -0.41 -0.29 -0.34
q28 -0.27 -0.37 -0.16 -0.03
Note:
Relative cut-off value is -0.096, which is 0.121 above the average correlation (-0.218).
Correlations above the cut-off are highlighted in red text.
Code
RIpartgamLD(d_psf_d)
Item 1 Item 2 Partial gamma SE Lower CI Upper CI Adjusted p-value (BH)
q28 q27 0.441 0.045 0.354 0.529 0.000
q27 q28 0.263 0.049 0.167 0.359 0.000
q24 q22 0.253 0.054 0.147 0.358 0.000
q28 q24 0.202 0.056 0.092 0.311 0.006
Code
RItargeting(d_psf_d)

Code
RIitemHierarchy(d_psf_d)

Code
mirt(d_psf_d, model=1, itemtype='Rasch', verbose = FALSE) %>% 
  plot(type="trace", as.table = TRUE, 
       theta_lim = c(-5,5))

Code
RIpfit(d_psf_d)

Code
RIpartgamDIF(d_psf_d, d_dif__psf_d$Kön)
Item Partial gamma SE Lower CI Upper CI Adjusted p-value (BH)
q24 0.413 0.058 0.300 0.525 0.000
q27 -0.326 0.057 -0.438 -0.215 0.000
q22 0.188 0.063 0.064 0.311 0.014
Code
RIdifTableLR(d_psf_d, d_dif__psf_d$Kön)
Item locations
Standard errors
Item Kille Tjej MaxDiff All SE_Kille SE_Tjej SE_All
q22 0.46 0.609 0.149 0.583 0.187 0.135 0.107
q23 0.103 0.383 0.28 0.269 0.174 0.138 0.107
q24 0.668 0.327 0.341 0.477 0.202 0.131 0.105
q27 0.302 0.783 0.481 0.599 0.209 0.158 0.125
q28 0.639 0.589 0.05 0.585 0.237 0.149 0.124
Note:
Values highlighted in red are above the chosen cutoff 0.5 logits. Background color brown and blue indicate the lowest and highest values among the DIF groups.
Code
dif_depfig <- RIdifThreshFigLR(d_psf_d, d_dif__psf_d$Kön)
dif_depfig

Code
RIpartgamDIF(d_psf_d, d_dif__psf_d$Årskurs)
[1] "No statistically significant DIF found."
Code
RIdifTableLR(d_psf_d, d_dif__psf_d$Årskurs)
Item locations
Standard errors
Item Åk 9 Gy 2 MaxDiff All SE_Åk 9 SE_Gy 2 SE_All
q22 0.581 0.586 0.005 0.583 0.142 0.162 0.107
q23 0.251 0.29 0.039 0.269 0.143 0.162 0.107
q24 0.569 0.374 0.195 0.477 0.144 0.154 0.105
q27 0.703 0.48 0.223 0.599 0.171 0.183 0.125
q28 0.609 0.562 0.047 0.585 0.164 0.188 0.124
Note:
Values highlighted in red are above the chosen cutoff 0.5 logits. Background color brown and blue indicate the lowest and highest values among the DIF groups.
Code
RIdifThreshFigLR(d_psf_d, d_dif__psf_d$Årskurs)

  • Mokken visar samma dimension
  • ingen underfit
  • q28 möjligen overfit
  • PCA 1.61
  • Lokalt beroende mellan q28 och q27 (PHQ-2)
  • Targeting visar stora golveffekter: svårt att mäta lägre nivåer av psykisk ohälsa
  • Svarskategorier
  • Inga problem med invarians

Vi tar bort item 27.

Code
removed_items <- c("q27")
Code
d_backup_psf_d <- d_psf_d

d_psf_d <- d_psf_d %>% 
  select(!any_of(removed_items))
Code
# d_psf_d <- d_psf_d %>%
#   mutate(across(any_of(c("q27", "q28")), ~ car::recode(.x, "4=3")))

3.16 Analys 2 - depression

itemnr item
q22 du känner att du inte duger?
q23 du känner dig slö och olustig?
q24 du känner dig ledsen eller deppig utan att veta varför?
q28 Känt dig nedstämd eller upplevt en känsla av hopplöshet
Code
d_psf_d %>% 
  RIbootRestscore(iterations = 250, samplesize = 600, cpu = 8)
Item Item-restscore result % of iterations Conditional MSQ infit Relative average item location
q23 underfit 20.8 1.12 1.11
q24 overfit 47.2 0.86 1.33
Note:
Results based on 250 bootstrap iterations with n = 600 and 4 items. Conditional mean-square infit based on complete responders only (n = 1369).
Code
RIpcmPCA(d_psf_d)

PCA of Rasch model residuals

Eigenvalues Proportion of variance
1.49 39.2%
1.26 32.4%
1.24 28.2%
0.01 0.2%
Code
RIloadLoc(d_psf_d)

Code
RIbootLRT(d_psf_d, samplesize = 400, cpu = 8)
Result n Percent
Not statistically significant 392 39.2
Statistically significant 608 60.8
Code
RIpartgamLD(d_psf_d)
Item 1 Item 2 Partial gamma SE Lower CI Upper CI Adjusted p-value (BH)
q24 q28 0.306 0.054 0.200 0.413 0.000
q28 q24 0.175 0.057 0.062 0.288 0.028
Code
simcor2 <- RIgetResidCor(d_psf_d, iterations = 500, cpu = 8)

RIresidcorr(d_psf_d, cutoff = simcor2$p999)
q22 q23 q24 q28
q22
q23 -0.21
q24 -0.25 -0.25
q28 -0.36 -0.41 -0.21
Note:
Relative cut-off value is -0.141, which is 0.139 above the average correlation (-0.28).
Correlations above the cut-off are highlighted in red text.
Code
RItargeting(d_psf_d)

Code
RIitemHierarchy(d_psf_d)

Code
mirt(d_psf_d, model=1, itemtype='Rasch', verbose = FALSE) %>% 
  plot(type="trace", as.table = TRUE, 
       theta_lim = c(-5,5))

Code
RIpfit(d_psf_d)

Code
RIpartgamDIF(d_psf_d, d_dif__psf_d$Kön)
Item Partial gamma SE Lower CI Upper CI Adjusted p-value (BH)
q24 0.309 0.065 0.181 0.437 0.000
q23 -0.212 0.065 -0.338 -0.085 0.004
Code
RIdifTableLR(d_psf_d, d_dif__psf_d$Kön)
Item locations
Standard errors
Item Kille Tjej MaxDiff All SE_Kille SE_Tjej SE_All
q22 0.468 0.689 0.221 0.639 0.195 0.137 0.110
q23 0.067 0.463 0.396 0.308 0.183 0.140 0.110
q24 0.699 0.405 0.294 0.529 0.211 0.133 0.108
q28 0.697 0.665 0.032 0.652 0.246 0.152 0.127
Note:
Values highlighted in red are above the chosen cutoff 0.5 logits. Background color brown and blue indicate the lowest and highest values among the DIF groups.
Code
RIdifThreshFigLR(d_psf_d, d_dif__psf_d$Kön)

Code
RIpartgamDIF(d_psf_d, d_dif__psf_d$Årskurs)
[1] "No statistically significant DIF found."
Code
RIdifTableLR(d_psf_d, d_dif__psf_d$Årskurs)
Item locations
Standard errors
Item Åk 9 Gy 2 MaxDiff All SE_Åk 9 SE_Gy 2 SE_All
q22 0.644 0.633 0.011 0.639 0.146 0.166 0.110
q23 0.309 0.306 0.003 0.308 0.147 0.167 0.110
q24 0.633 0.406 0.227 0.529 0.148 0.159 0.108
q28 0.677 0.624 0.053 0.652 0.168 0.194 0.127
Note:
Values highlighted in red are above the chosen cutoff 0.5 logits. Background color brown and blue indicate the lowest and highest values among the DIF groups.
Code
RIdifThreshFigLR(d_psf_d, d_dif__psf_d$Årskurs)

Code
d_psf_d %>% 
  #select(!any_of(removed_items)) %>% 
  RItif(samplePSI = T)

Enda kvarstående problemet är översta svarskategorierna för q28.

3.17 Analys 1 Ångest/oro

itemnr item
q21 du känner dig rädd utan att veta varför?
q25 Känt dig nervös, orolig eller spänd
q26 Haft svårt att sluta oroa dig eller kontrollera din oro
Code
RIbootRestscore(d_psf_å, iterations = 250, samplesize = 600, cpu = 8)
Item Item-restscore result % of iterations Conditional MSQ infit Relative average item location
q21 underfit 99.6 1.35 2.69
q26 overfit 100.0 0.66 1.45
q25 overfit 42.0 0.87 0.39
Note:
Results based on 250 bootstrap iterations with n = 600 and 3 items. Conditional mean-square infit based on complete responders only (n = 1374).
Code
RIloadLoc(d_psf_å)

Code
RIbootLRT(d_psf_å, samplesize = 400, cpu = 8) 
Result n Percent
Not statistically significant 1000 100

Item 21 passar inte in med 25 och 26. D.v.s. det mäter inte samma underliggande variabel.

3.18 Analys PHQ-2 (q27 + q28)

Code
d_psf_d <- d %>% 
  select(Kön, Årskurs, Bostad, any_of(c("q22", "q23", "q24", "q27", "q28")))%>% 
  na.omit() %>% 
  select(q27,q28)
itemnr item
q27 Minskat intresse eller glädje att göra saker
q28 Känt dig nedstämd eller upplevt en känsla av hopplöshet
Code
d_psf_d %>% 
  RIbootRestscore(iterations = 200, samplesize = 600, cpu = 8)
Item Item-restscore result % of iterations Conditional MSQ infit Relative average item location
Note:
Results based on 200 bootstrap iterations with n = 600 and 2 items. Conditional mean-square infit based on complete responders only (n = 1369).
Code
RIbootLRT(d_psf_d, samplesize = 400, cpu = 8)
Result n Percent
Not statistically significant 1000 100
Code
RItargeting(d_psf_d)

Code
RIitemHierarchy(d_psf_d)

Code
mirt(d_psf_d, model=1, itemtype='Rasch', verbose = FALSE) %>% 
  plot(type="trace", as.table = TRUE, 
       theta_lim = c(-5,5))

Code
RIpfit(d_psf_d)

Code
RIpartgamDIF(d_psf_d, d_dif__psf_d$Kön)
Item Partial gamma SE Lower CI Upper CI Adjusted p-value (BH)
q27 -0.259 0.073 -0.403 -0.116 0.001
q28 0.259 0.073 0.116 0.403 0.001
Code
RIdifTableLR(d_psf_d, d_dif__psf_d$Kön)
Item locations
Standard errors
Item Kille Tjej MaxDiff All SE_Kille SE_Tjej SE_All
q27 0.315 0.977 0.662 0.671 0.244 0.230 0.161
q28 0.679 0.621 0.058 0.640 0.275 0.199 0.155
Note:
Values highlighted in red are above the chosen cutoff 0.5 logits. Background color brown and blue indicate the lowest and highest values among the DIF groups.
Code
RIdifThreshFigLR(d_psf_d, d_dif__psf_d$Kön)

Code
RIpartgamDIF(d_psf_d, d_dif__psf_d$Årskurs)
[1] "No statistically significant DIF found."
Code
RIdifTableLR(d_psf_d, d_dif__psf_d$Årskurs)
Item locations
Standard errors
Item Åk 9 Gy 2 MaxDiff All SE_Åk 9 SE_Gy 2 SE_All
q27 0.857 0.495 0.362 0.671 0.236 0.223 0.161
q28 0.707 0.584 0.123 0.640 0.219 0.224 0.155
Note:
Values highlighted in red are above the chosen cutoff 0.5 logits. Background color brown and blue indicate the lowest and highest values among the DIF groups.
Code
RIdifThreshFigLR(d_psf_d, d_dif__psf_d$Årskurs)

Code
RIpartgamDIF(d_psf_d, d_dif__psf_d$Bostad)
[1] "No statistically significant DIF found."
Code
#RIdifTableLR(d_v, d_dif_v$Bostad)
#RIdifThreshFigLR(d_v, d_dif_v$Bostad)
#RIciccPlot(d_rest, dif = "yes", dif_var = d_dif_rest$year)
Code
d_psf_d %>% 
  #select(!any_of(removed_items)) %>% 
  RItif(samplePSI = T)

Code
removed_items <- c("q21")
Code
d_psf_å <- d_psf_å %>% 
  select(!any_of(removed_items))

3.19 Analys GAD-2 (q25 + q26)

Code
d_psf_å <- d_psf_å %>% 
  select(q25,q26)
itemnr item
q25 Känt dig nervös, orolig eller spänd
q26 Haft svårt att sluta oroa dig eller kontrollera din oro
Code
d_psf_å %>% 
  RIbootRestscore(iterations = 250, samplesize = 600, cpu = 8)
Item Item-restscore result % of iterations Conditional MSQ infit Relative average item location
Note:
Results based on 250 bootstrap iterations with n = 600 and 2 items. Conditional mean-square infit based on complete responders only (n = 1374).
Code
RIbootLRT(d_psf_å, samplesize = 400, cpu = 8)
Result n Percent
Not statistically significant 1000 100
Code
RItargeting(d_psf_å)

Code
RIitemHierarchy(d_psf_å)

Code
mirt(d_psf_å, model=1, itemtype='Rasch', verbose = FALSE) %>% 
  plot(type="trace", as.table = TRUE, 
       theta_lim = c(-5,5))

Code
RIpfit(d_psf_å)

Code
RIpartgamDIF(d_psf_å, d_dif__psf_å$Kön)
[1] "No statistically significant DIF found."
Code
RIdifTableLR(d_psf_å, d_dif__psf_å$Kön)
Item locations
Standard errors
Item Kille Tjej MaxDiff All SE_Kille SE_Tjej SE_All
q25 0.034 0.427 0.393 0.273 0.297 0.274 0.196
q26 1.754 1.946 0.192 1.838 0.364 0.251 0.189
Note:
Values highlighted in red are above the chosen cutoff 0.5 logits. Background color brown and blue indicate the lowest and highest values among the DIF groups.
Code
RIdifThreshFigLR(d_psf_å, d_dif__psf_å$Kön)

Code
RIpartgamDIF(d_psf_å, d_dif__psf_å$Årskurs)
[1] "No statistically significant DIF found."
Code
RIdifTableLR(d_psf_å, d_dif__psf_å$Årskurs)
Item locations
Standard errors
Item Åk 9 Gy 2 MaxDiff All SE_Åk 9 SE_Gy 2 SE_All
q25 0.339 0.186 0.153 0.273 0.259 0.314 0.196
q26 1.8 1.908 0.108 1.838 0.255 0.288 0.189
Note:
Values highlighted in red are above the chosen cutoff 0.5 logits. Background color brown and blue indicate the lowest and highest values among the DIF groups.
Code
RIdifThreshFigLR(d_psf_å, d_dif__psf_å$Årskurs)

Code
d_psf_å %>% 
  #select(!any_of(removed_items)) %>% 
  RItif(samplePSI = T)

3.20 Analys GAD+PHQ

Code
d_psf_d <- d %>% 
  select(q25:q28) %>% 
  na.omit()
itemnr item
q25 Känt dig nervös, orolig eller spänd
q26 Haft svårt att sluta oroa dig eller kontrollera din oro
q27 Minskat intresse eller glädje att göra saker
q28 Känt dig nedstämd eller upplevt en känsla av hopplöshet
Code
aisp(d_psf_d) %>% 
  as.data.frame() %>% 
  set_names("h > 0.3") %>% 
  arrange(`h > 0.3`) %>% 
  kbl_rise(tbl_width = 20)
h > 0.3
q25 1
q26 1
q27 1
q28 1
Code
d_psf_d %>% 
  RIbootRestscore(iterations = 250, samplesize = 600, cpu = 8)
Item Item-restscore result % of iterations Conditional MSQ infit Relative average item location
q27 underfit 45.6 1.22 1.63
q26 overfit 85.6 0.81 1.41
q28 overfit 14.0 0.92 1.61
Note:
Results based on 250 bootstrap iterations with n = 600 and 4 items. Conditional mean-square infit based on complete responders only (n = 1378).
Code
RIpcmPCA(d_psf_d)

PCA of Rasch model residuals

Eigenvalues Proportion of variance
1.92 50.4%
1.11 28.7%
0.97 20.6%
0.01 0.3%
Code
simpca <- RIbootPCA(d_psf_d,cpu = 8)
simpca$max
[1] 1.46
Code
RIloadLoc(d_psf_d)

Code
RIbootLRT(d_psf_d, samplesize = 400, cpu = 8)
Result n Percent
Not statistically significant 551 55.1
Statistically significant 449 44.9
Code
simcor4 <- RIgetResidCor(d_psf_d, iterations = 500, cpu = 8)
RIresidcorr(d_psf_d, cutoff = simcor4$p999)
q25 q26 q27 q28
q25
q26 0.08
q27 -0.5 -0.49
q28 -0.46 -0.35 -0.03
Note:
Relative cut-off value is -0.19, which is 0.102 above the average correlation (-0.292).
Correlations above the cut-off are highlighted in red text.
Code
RIpartgamLD(d_psf_d)
Item 1 Item 2 Partial gamma SE Lower CI Upper CI Adjusted p-value (BH)
q26 q25 0.578 0.039 0.502 0.654 0
q25 q26 0.471 0.042 0.389 0.552 0
q28 q27 0.429 0.046 0.339 0.519 0
q27 q28 0.294 0.049 0.199 0.390 0
Code
RItargeting(d_psf_d)

Code
RIitemHierarchy(d_psf_d)

Code
mirt(d_psf_d, model=1, itemtype='Rasch', verbose = FALSE) %>% 
  plot(type="trace", as.table = TRUE, 
       theta_lim = c(-5,5))

Code
RIpfit(d_psf_d)

Även om item-restscore inte indikerar någon klar problematik med dimensionaliteten så finns påtagliga residualkorrelationer mellan de två item-paren.

3.21 Preliminär riskgruppsanalys

Vi använder ordinal sum score >= 5 som cutoff (fem eller högre), utifrån att 3 normalt sett använts, men vi har lagt till en svarskategori som den nästa lägsta.

3.21.1 Depression PHQ-2

Code
phq2 <- d %>% 
  select(q22:q24,q27,q28,Kön,Årskurs) %>% 
  na.omit() %>% 
  mutate(phq2_sum = q27 + q28) %>% 
  mutate(phq_risk = case_when(phq2_sum >= 5 ~ "at_risk",
                              TRUE ~ "no_risk"))

phq2 %>%
  group_by(Kön) %>% 
  count(phq_risk) %>% 
  mutate(percent = n*100/sum(n)) %>% 
  kable()
Kön phq_risk n percent
Kille at_risk 50 7.575758
Kille no_risk 610 92.424242
Tjej at_risk 118 16.573034
Tjej no_risk 594 83.426966

Mer än dubbelt så stor andel bland flickor.

3.21.2 Depression gamla frågor

Utifrån targeting-figuren i analysen med alla depressions items har vi sum score >=6 på items q22+q23+q24 som motsvarar samma mätvärde (theta) som ovan använda cutoff för q27 och q28.

Code
sthlm_psf_dep <- d %>% 
  select(q22:q24,q27,q28,Kön,Årskurs) %>% 
  na.omit() %>% 
  mutate(dep_sum = q22 + q23 + q24) %>% 
  mutate(dep_risk = case_when(dep_sum >= 6 ~ "at_risk",
                              TRUE ~ "no_risk"))

sthlm_psf_dep %>%
  group_by(Kön) %>% 
  count(dep_risk) %>% 
  mutate(percent = n*100/sum(n)) %>% 
  kable()
Kön dep_risk n percent
Kille at_risk 46 6.969697
Kille no_risk 614 93.030303
Tjej at_risk 117 16.432584
Tjej no_risk 595 83.567416

Snarlika siffror. Lite större skillnad för pojkarna.

3.21.3 Depression jämförelse

Vi behöver korsvalidera detta för att se om jämförelsen är stabil även när vi varierar samplet. Korsvalidering gör en slumpmässig indelning av samplet, i vårt fall används 10 delar (subsampel). Sedan upprepas testet 10 gånger, varje gång med något subsampel borttaget. Vi stratifierar indelningen av samplet på Årskurs för att säkerställa likvärdighet i subsamplen.

Code
library(rsample)

d_all <- d %>% 
  select(q22:q24,q27,q28,Kön,Årskurs) %>% 
  na.omit() %>% 
  mutate(dep_sum = q22 + q23 + q24) %>% 
  mutate(dep_risk = case_when(dep_sum >= 6 ~ "at_risk",
                              TRUE ~ "no_risk")) %>% 
  mutate(phq2_sum = q27 + q28) %>% 
  mutate(phq_risk = case_when(phq2_sum >= 5 ~ "at_risk",
                              TRUE ~ "no_risk"))

set.seed(8445)
d_folds <- vfold_cv(d_all, v = 10, strata = Årskurs)



gamla <- map_dfr(1:10, ~ analysis(d_folds$splits[[.x]]) %>% 
  group_by(Kön) %>% 
  count(dep_risk) %>% 
  mutate(percent = n*100/sum(n))) %>% 
  ungroup() %>% 
  group_by(Kön,dep_risk) %>% 
  summarise(mean = mean(percent),
            lower = min(percent),
            upper = max(percent)) %>% 
  ungroup() %>% 
  add_column(items = "Gamla frågor")

nya <- map_dfr(1:10, ~ analysis(d_folds$splits[[.x]]) %>% 
  group_by(Kön) %>% 
  count(phq_risk) %>% 
  mutate(percent = n*100/sum(n))) %>% 
  ungroup() %>% 
  group_by(Kön,phq_risk) %>% 
  summarise(mean = mean(percent),
            lower = min(percent),
            upper = max(percent)) %>% 
  ungroup() %>% 
  add_column(items = "PHQ-2") %>% 
  rename(dep_risk = phq_risk)

rbind(gamla,nya) %>% 
  filter(dep_risk == "at_risk") %>% 
  arrange(Kön) %>% 
  knitr::kable()
Kön dep_risk mean lower upper items
Kille at_risk 6.970352 6.655574 7.370184 Gamla frågor
Kille at_risk 7.575479 7.130435 7.952623 PHQ-2
Tjej at_risk 16.430586 14.913658 17.219589 Gamla frågor
Tjej at_risk 16.572679 15.855573 17.031250 PHQ-2
Code
nya_alla <- map_dfr(1:10, ~ analysis(d_folds$splits[[.x]]) %>% 
  group_by(Kön) %>% 
  count(phq_risk) %>% 
  mutate(percent = n*100/sum(n))) %>% 
  ungroup() %>% 
  rename(dep_risk = phq_risk) %>% 
  add_column(items = "PHQ-2") 

gamla_alla <- map_dfr(1:10, ~ analysis(d_folds$splits[[.x]]) %>% 
  group_by(Kön) %>% 
  count(dep_risk) %>% 
  mutate(percent = n*100/sum(n))) %>% 
  ungroup() %>% 
  add_column(items = "Gamla frågor")

library(ggdist)
rbind(gamla_alla,nya_alla) %>% 
  filter(dep_risk == "at_risk") %>% 
  ggplot(aes(y = items, x = percent)) +
  # geom_point(position = position_dodge(width = 0.5)) +
  # geom_errorbar(aes(ymin = lower, ymax = upper),
  #               position = position_dodge(width = 0.5),
  #               width = 0.3)
  stat_dotsinterval(point_interval = "mean_qi", .width = 1) +
  facet_wrap(~Kön, ncol = 1) +
  scale_x_continuous(breaks = scales::breaks_pretty(10)) +
  theme_rise() +
  labs(y = NULL, x = "Andel elever indikerade med risk för depression",
       title = "Jämförelse mellan gamla och nya frågor avseende risk för depression",
       subtitle = "Resultat från korsvalidering med k = 10",
       caption = "Svart punkt visar medelvärde, linjerna visar lägsta-högsta värde från korsvalideringen.")

Code
rbind(gamla,nya) %>% 
  filter(dep_risk == "at_risk") %>% 
  ggplot(aes(y = mean, x = Kön, color = items)) +
  geom_point(position = position_dodge(width = 0.5),
             size = 4, shape = 18) +
  geom_errorbar(aes(ymin = lower, ymax = upper),
                position = position_dodge(width = 0.5),
                width = 0.15) +
  labs(x = NULL, color = NULL,
       y = "Andel elever indikerade med risk för depression",
       title = "Jämförelse mellan gamla och nya frågor avseende risk för depression",
       subtitle = "Resultat från korsvalidering med k = 10",
       caption = "Punkter visar medelvärde, linjerna visar lägsta-högsta värde från korsvalideringen.") +
  scale_y_continuous(breaks = scales::breaks_pretty(10)) +
  theme_rise()

Det finns lite DIF för kön för gamla items, vilket kan vara det som orsakar att pojkarna har aningen större skillnad i riskidentifikation mellan gamla och nya items. PHQ-2 verkar stabilare än de gamla frågorna, vilket framgår i resultatet för flickorna.

Code
dif_depfig + theme_rise()

3.22 Programvara som använts för analyserna

Code
# pkgs <- cite_packages(cite.tidyverse = TRUE, 
#                       output = "table",
#                       bib.file = "grateful-refs.bib",
#                       include.RStudio = TRUE,
#                       out.dir = getwd())
# formattable(pkgs, 
#             table.attr = 'class=\"table table-striped\" style="font-size: 15px; font-family: Lato; width: 80%"')
Code
R version 4.4.3 (2025-02-28)
Platform: aarch64-apple-darwin20
Running under: macOS Sequoia 15.6

Matrix products: default
BLAS:   /Library/Frameworks/R.framework/Versions/4.4-arm64/Resources/lib/libRblas.0.dylib 
LAPACK: /Library/Frameworks/R.framework/Versions/4.4-arm64/Resources/lib/libRlapack.dylib;  LAPACK version 3.12.0

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

time zone: Europe/Stockholm
tzcode source: internal

attached base packages:
 [1] parallel  grid      stats4    stats     graphics  grDevices utils    
 [8] datasets  methods   base     

other attached packages:
 [1] gtsummary_2.3.0      labelled_2.13.0      haven_2.5.4         
 [4] foreign_0.8-88       easyRasch_0.3.6.3    doParallel_1.0.17   
 [7] iterators_1.0.14     furrr_0.3.1          future_1.67.0       
[10] foreach_1.5.2        ggdist_3.3.3         janitor_2.2.1       
[13] hexbin_1.28.4        catR_3.17            glue_1.8.0          
[16] formattable_0.2.1    patchwork_1.3.0      knitr_1.48          
[19] reshape_0.8.9        matrixStats_1.4.1    psychotree_0.16-2   
[22] psychotools_0.7-4    partykit_1.2-24      mvtnorm_1.3-1       
[25] libcoin_1.0-10       psych_2.5.6          iarm_0.4.3          
[28] mirt_1.44.0          lattice_0.22-6       eRm_1.0-10          
[31] lubridate_1.9.4      forcats_1.0.0        stringr_1.5.1       
[34] dplyr_1.1.4          purrr_1.1.0          readr_2.1.5         
[37] tidyr_1.3.1          tibble_3.3.0         tidyverse_2.0.0     
[40] readxl_1.4.5         kableExtra_1.4.0     grateful_0.2.4      
[43] car_3.1-2            carData_3.0-5        ggrepel_0.9.6       
[46] ggplot2_3.5.2        arrow_16.1.0         mokken_3.1.2        
[49] poLCA_1.6.0.1        MASS_7.3-64          scatterplot3d_0.3-44

loaded via a namespace (and not attached):
 [1] RColorBrewer_1.1-3   vcd_1.4-12           rstudioapi_0.17.1   
 [4] audio_0.1-11         jsonlite_1.8.9       magrittr_2.0.3      
 [7] farver_2.1.2         rmarkdown_2.28       vctrs_0.6.5         
[10] base64enc_0.1-3      htmltools_0.5.8.1    distributional_0.4.0
[13] curl_6.2.2           cellranger_1.1.0     Formula_1.2-5       
[16] dcurver_0.9.2        parallelly_1.45.0    htmlwidgets_1.6.4   
[19] plyr_1.8.9           testthat_3.2.1.1     zoo_1.8-12          
[22] lifecycle_1.0.4      pkgconfig_2.0.3      Matrix_1.7-2        
[25] R6_2.5.1             fastmap_1.2.0        snakecase_0.11.1    
[28] digest_0.6.37        colorspace_2.1-1     rprojroot_2.0.4     
[31] Hmisc_5.2-3          vegan_2.6-8          labeling_0.4.3      
[34] progressr_0.14.0     timechange_0.3.0     abind_1.4-5         
[37] mgcv_1.9-1           compiler_4.4.3       here_1.0.1          
[40] vcdExtra_0.8-5       bit64_4.0.5          withr_3.0.2         
[43] htmlTable_2.4.3      backports_1.5.0      relimp_1.0-5        
[46] R.utils_2.12.3       sessioninfo_1.2.3    GPArotation_2024.3-1
[49] permute_0.9-7        tools_4.4.3          lmtest_0.9-40       
[52] future.apply_1.20.0  nnet_7.3-20          R.oo_1.26.0         
[55] nlme_3.1-167         inum_1.0-5           checkmate_2.3.2     
[58] cluster_2.1.8        generics_0.1.3       snow_0.4-4          
[61] gtable_0.3.5         RPushbullet_0.3.4    tzdb_0.4.0          
[64] R.methodsS3_1.8.2    ca_0.71.1            data.table_1.17.8   
[67] hms_1.1.3            xml2_1.3.6           Deriv_4.1.3         
[70] pillar_1.10.1        splines_4.4.3        survival_3.8-3      
[73] bit_4.0.5            tidyselect_1.2.1     pbapply_1.7-2       
[76] gridExtra_2.3        svglite_2.1.3        xfun_0.46           
[79] gnm_1.1-5            brio_1.1.5           stringi_1.8.4       
[82] yaml_2.3.10          evaluate_1.0.1       codetools_0.2-20    
[85] beepr_2.0            cli_3.6.3            rpart_4.1.24        
[88] qvcalc_1.0.3         systemfonts_1.1.0    Rcpp_1.0.14         
[91] globals_0.18.0       assertthat_0.2.1     listenv_0.9.1       
[94] viridisLite_0.4.2    SimDesign_2.17.1     scales_1.4.0        
[97] rlang_1.1.6          mnormt_2.1.1        

3.23 Referenser