Statistika - Zadaća 3

Z3: Linearne i nelinearne regresije


library(readxl)
library(corrplot)
corrplot 0.95 loaded
library(Hmisc)

Attaching package: 'Hmisc'
The following objects are masked from 'package:base':

    format.pval, units
library(ggplot2)
library(car)
Loading required package: carData
library(pROC)
Type 'citation("pROC")' for a citation.

Attaching package: 'pROC'
The following objects are masked from 'package:stats':

    cov, smooth, var
library(ResourceSelection)
ResourceSelection 0.3-6      2023-06-27
# ================================================================
# UČITAVANJE PODATAKA
# ================================================================
df <- read_excel("/Users/lucijalibric/Desktop/Statistika/VJ3_regresija.xlsx")

colnames(df) <- c("RB", "SPOL", "Skupina", "Killip", "DaniUBolnici",
                  "SE", "Eritrociti", "Hgb", "Htc", "MCV", "MCHC",
                  "Leukocit", "Trombocit", "Glukoza", "Urea", "Kreatinin",
                  "Kalij", "eGFR", "AST", "ALT", "LDH1", "LDH2",
                  "Bilirubin", "Kolesterol", "HDL", "LDL", "Trigliceridi",
                  "CRP1", "CRP2", "CRP3", "Trop1", "Trop2", "Trop3",
                  "HSP90_1", "HSP90_2", "HSP90_3", "Var45")

1.dio: Jednostruka i višestruka linearna regresija
Napraviti jednostruku korelacijsku analizu za odabrani primjer iz baze podataka i interpretirati rezultate (pazite na odabir varijabli i zadovoljnost uvjeta za primjenu Pearson/Spearman korelacije)

Odabrane varijable: CRP (1. mjerenje) i Troponin (1. mjerenje)

Istraživačko pitanje:

Postoji li statistički značajna povezanost između razine upalnog markera CRP-a (1. mjerenje) i razine Troponina I (1. mjerenje) u ispitanih bolesnika/pacijenata?

H0: nema povezanosti između razine CRP-a (1. mjerenje) i razine Troponina (1. mjerenje)

H1: postoji povezanost između razine CRP-a (1. mjerenje) i razine Troponina (1. mjerenje)

Provjera uvjeta:

# ================================================================
# 1. DIO — KORELACIJSKA ANALIZA: CRP1 ~ SE
# ================================================================

# Shapiro-Wilk test normalnosti
shapiro.test(df$CRP1)

    Shapiro-Wilk normality test

data:  df$CRP1
W = 0.90867, p-value = 1.926e-07
shapiro.test(df$Trop1)

    Shapiro-Wilk normality test

data:  df$Trop1
W = 0.62352, p-value < 2.2e-16

Shapiro-Wilk test pokazao je da niti CRP1 niti Trop1 nisu normalno distribuirani (p < 0,05 za obje varijable) → primjenjujemo Spearmanovu korelaciju.

Vizualizacija za sve:

# Corrplot za vizualizaciju 
stupci <- c("CRP1", "SE", "Eritrociti", "Hgb", "Leukocit", 
            "Trombocit", "Glukoza", "Urea", "Kreatinin", 
            "Kalij", "eGFR", "AST", "ALT", "LDH1", 
            "Bilirubin", "Kolesterol", "HDL", "LDL", 
            "Trigliceridi", "Trop1", "HSP90_1",
            "DaniUBolnici", "Killip")

prediktori_mat <- as.matrix(df[, stupci])

# Korelacijska matrica
kor_r <- cor(prediktori_mat, method = "spearman")

# Corrplot
corrplot(kor_r,
         method = "color",
         type = "upper",
         order = "original",
         tl.cex = 0.7,
         tl.col = "black",
         addCoef.col = "black",
         number.cex = 0.5,
         title = "Korelacijska matrica",
         mar = c(0, 0, 1, 0))

# Spearman korelacija za naš primjer
cor.test(df$CRP1, df$Trop1, method = "spearman")
Warning in cor.test.default(df$CRP1, df$Trop1, method = "spearman"): Cannot
compute exact p-value with ties

    Spearman's rank correlation rho

data:  df$CRP1 and df$Trop1
S = 258445, p-value = 0.0001381
alternative hypothesis: true rho is not equal to 0
sample estimates:
      rho 
0.3257487 
# Procjena koeficijenta korelacije u populaciji
r <- 0.326
n <- 132

# Standardna greška korelacije
SE_r <- sqrt((1 - r^2) / (n - 2))
cat("r =", r, "\n")
r = 0.326 
cat("SE_r =", round(SE_r, 4), "\n")
SE_r = 0.0829 
# 95% interval pouzdanosti
CI_low <- r - 1.96 * SE_r
CI_high <- r + 1.96 * SE_r
cat("95% CI: (", round(CI_low, 3), "-", round(CI_high, 3), ")\n")
95% CI: ( 0.163 - 0.489 )

Spearmanova korelacija

  • p < 0,001 → odbacujemo H0

  • r (Spearman ρ) = 0,326 (Spearmanov koeficijent korelacije u populaciji) 

  • SE_r = 0,083

  • 95% CI: (0,163 – 0,489) - s 95% pouzdanošću tvrdimo da se pravi koeficijent korelacije u populaciji nalazi između 0,163 i 0,489

Kod odbacivanja nul hipoteze (postoji povezanost) Spearmanov koeficijent korelacije ne bi se smio interpretirati kao Pearsonov – bolju interpretaciju daje Kendall Tau koeficijent korelacije rangova:

cor.test(df$CRP1, df$Trop1, method = "kendall")

    Kendall's rank correlation tau

data:  df$CRP1 and df$Trop1
z = 4.284, p-value = 1.835e-05
alternative hypothesis: true tau is not equal to 0
sample estimates:
      tau 
0.2557621 
# Izračun OR za Kendall tau
tau <- 0.256
OR_kendall <- (1 + tau) / (1 - tau)
cat("Kendall τ =", tau, "\n")
Kendall τ = 0.256 
cat("OR (pc/pd) =", round(OR_kendall, 3), "\n")
OR (pc/pd) = 1.688 
cat("Interpretacija: vjerojatnost pojave konkordantnih parova je",
    round(OR_kendall, 2), "puta veća od diskonkordantnih\n")
Interpretacija: vjerojatnost pojave konkordantnih parova je 1.69 puta veća od diskonkordantnih

p < 0,001, tau = 0,256 → pozitivna korelacija između razine upalnog markera CRP-a (1. mjerenje) i razine Troponina I (1. mjerenje) kod ispitanika iz ovog istraživanja

Vjerojatnost pojave konkordantnih parova (dva ispitanika gdje onaj s višim CRP-om ima i viši Troponin) je 1,69 puta veća od vjerojatnosti pojave diskonkordantnih parova.

ggplot(df, aes(x = Trop1, y = CRP1)) +
  geom_point(alpha = 0.5, color = "#2E86C1", size = 2) +
  geom_smooth(method = "lm", color = "#E74C3C", 
              se = TRUE, linewidth = 1) +
  annotate("text", x = max(df$Trop1, na.rm = TRUE) * 0.7, 
           y = max(df$CRP1, na.rm = TRUE) * 0.9,
           label = paste0("Spearman ρ = 0.326\nKendall τ = 0.256\np < 0.001"),
           color = "#2E86C1", size = 4) +
  labs(title = "Korelacija CRP1 i Troponina I",
       subtitle = "Spearmanova korelacija rangova",
       x = "Troponin I - 1. mjerenje",
       y = "CRP1 (mg/L)") +
  theme_minimal(base_size = 12)
`geom_smooth()` using formula = 'y ~ x'

  • Trop1 ima outliere koji rastežu x os i čine da većina točaka izgleda zbijeno

Vizualizacija s log transformacijom x osi:

U medicinskim istraživanjima log transformacija Troponina je uobičajena praksa, ali ju koristimo samo za vizualizaciju

ggplot(df, aes(x = Trop1, y = CRP1)) +
  geom_point(alpha = 0.5, color = "#2E86C1", size = 2) +
  geom_smooth(method = "lm", color = "#E74C3C",
              se = TRUE, linewidth = 1) +
  scale_x_log10() +
  annotate("text", x = 30,
           y = max(df$CRP1, na.rm = TRUE) * 0.9,
           label = paste0("Spearman ρ = 0.326\nKendall τ = 0.256\np < 0.001"),
           color = "#2E86C1", size = 4) +
  labs(title = "Korelacija CRP1 i Troponina I",
       subtitle = "Spearmanova korelacija rangova",
       x = "Troponin I - 1. mjerenje (log skala)",
       y = "CRP1 (mg/L)") +
  theme_minimal(base_size = 12)
`geom_smooth()` using formula = 'y ~ x'

Zaključak:

Utvrđena je statistički značajna slaba pozitivna korelacija između CRP1 i Troponina I (Kendall τ = 0,256; p < 0,001). Vjerojatnost pojave konkordantnih parova je 1,69 puta veća od vjerojatnosti pojave diskonkordantnih parova, što znači da bolesnici s višim CRP-om imaju tendenciju imati i viši Troponin I. Procijenjeni Spearmanov koeficijent korelacije u populaciji iznosi ρ = 0,326 (SE = 0,083), a 95% interval pouzdanosti (0,163 – 0,489) ne uključuje nulu, što potvrđuje statističku značajnost korelacije u populaciji.

Odbacujemo H₀ — postoji statistički značajna pozitivna povezanost između razine CRP-a i Troponina I u ispitanih bolesnika. 


Pomoću višestruke regresijske analize naći prediktore za jednu od varijabli po izboru iz baze podataka (sugestija: odaberite CRP ili Trop ili HSP90) i interpretirati rezultate. Ocijenite model

Istraživačko pitanje:

Koji klinički i laboratorijski parametri su neovisni prediktori razine CRP-a (1. mjerenje) u ispitanih bolesnika?

# ================================================================
# 1. DIO — VIŠESTRUKA REGRESIJA: CRP1 ~ prediktori
# ================================================================

# KORAK 1: Inicijalni model sa svim prediktorima
model_reg <- lm(CRP1 ~ SE + Eritrociti + Hgb + Leukocit + Trombocit + 
                  Glukoza + Urea + Kreatinin + Kalij + eGFR +
                  AST + ALT + LDH1 + Bilirubin + Kolesterol + 
                  HDL + LDL + Trigliceridi + Trop1 + HSP90_1 +
                  DaniUBolnici + Killip,
                data = df)
summary(model_reg)

Call:
lm(formula = CRP1 ~ SE + Eritrociti + Hgb + Leukocit + Trombocit + 
    Glukoza + Urea + Kreatinin + Kalij + eGFR + AST + ALT + LDH1 + 
    Bilirubin + Kolesterol + HDL + LDL + Trigliceridi + Trop1 + 
    HSP90_1 + DaniUBolnici + Killip, data = df)

Residuals:
    Min      1Q  Median      3Q     Max 
-6.1049 -2.0236  0.2296  1.8746  6.9459 

Coefficients:
               Estimate Std. Error t value Pr(>|t|)    
(Intercept)  -4.1318772  6.6704811  -0.619 0.536928    
SE            0.0223833  0.0289084   0.774 0.440438    
Eritrociti    3.6409970  1.9865322   1.833 0.069556 .  
Hgb          -0.0427193  0.0582708  -0.733 0.465061    
Leukocit      0.3972492  0.1877881   2.115 0.036673 *  
Trombocit     0.0125039  0.0095067   1.315 0.191180    
Glukoza       0.0098941  0.4578808   0.022 0.982800    
Urea          0.3051989  0.2804276   1.088 0.278848    
Kreatinin    -0.0294662  0.0231803  -1.271 0.206372    
Kalij        -0.7304632  0.9953980  -0.734 0.464622    
eGFR         -0.0570799  0.0188702  -3.025 0.003103 ** 
AST          -0.0026400  0.0062388  -0.423 0.673009    
ALT          -0.0529621  0.0144211  -3.673 0.000374 ***
LDH1          0.0021774  0.0017563   1.240 0.217731    
Bilirubin    -0.0351308  0.0520107  -0.675 0.500818    
Kolesterol   -1.4168711  0.9634086  -1.471 0.144257    
HDL           1.4621266  1.5028033   0.973 0.332741    
LDL           1.3443425  0.9353316   1.437 0.153500    
Trigliceridi  1.2948248  0.6269365   2.065 0.041265 *  
Trop1         0.1019078  0.0290381   3.509 0.000654 ***
HSP90_1       0.0001153  0.0015594   0.074 0.941205    
DaniUBolnici  0.0166824  0.0652545   0.256 0.798702    
Killip        0.7509222  0.8109557   0.926 0.356506    
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 3.307 on 109 degrees of freedom
Multiple R-squared:  0.4892,    Adjusted R-squared:  0.3861 
F-statistic: 4.744 on 22 and 109 DF,  p-value: 1.998e-08
# KORAK 2: VIF provjera
vif(model_reg)
          SE   Eritrociti          Hgb     Leukocit    Trombocit      Glukoza 
    1.902460     7.673081     7.904898     4.176395     3.517904     1.423893 
        Urea    Kreatinin        Kalij         eGFR          AST          ALT 
    4.221066     3.712795     2.224936     3.440047     5.208694     2.781997 
        LDH1    Bilirubin   Kolesterol          HDL          LDL Trigliceridi 
    4.951286     1.534109    14.354893     2.795573    10.760080     2.660841 
       Trop1      HSP90_1 DaniUBolnici       Killip 
    1.829914     1.534235     1.500553     1.474656 

Problem s multikolinearnosti — neki VIF su visoki. Trebamo ukloniti problematične prediktore i napraviti čišći model.

U biomedicini uglavnom koristimo threshold od 5 ili 10, u ovom slučaju je korišten “stroži” (5).

Problematični prediktori:

# VIF vizualizacija
vif_df <- data.frame(
  Prediktor = names(vif(model_reg)),
  VIF = as.numeric(vif(model_reg))
)
ggplot(vif_df, aes(x = reorder(Prediktor, VIF), y = VIF, 
                   fill = VIF > 5)) +
  geom_bar(stat = "identity") +
  geom_hline(yintercept = 5, linetype = "dashed", 
             color = "#E74C3C", linewidth = 1) +
  scale_fill_manual(values = c("FALSE" = "#2E86C1", "TRUE" = "#E74C3C"),
                    labels = c("VIF ≤ 5", "VIF > 5")) +
  coord_flip() +
  labs(title = "VIF - inicijalni model",
       subtitle = "Crveno = multikolinearnost (VIF > 5)",
       x = "Prediktor", y = "VIF", fill = "") +
  theme_minimal(base_size = 12)

Uklanjamo: Kolesterol, LDL, Hgb, Eritrocite i AST

# KORAK 3: Reducirani model (uklonjen VIF > 5)
model_reg_red <- lm(CRP1 ~ SE + Leukocit + Trombocit + Glukoza + Urea + 
                      Kreatinin + Kalij + eGFR + ALT + LDH1 + Bilirubin + 
                      HDL + Trigliceridi + Trop1 + HSP90_1 +
                      DaniUBolnici + Killip,
                    data = df)
summary(model_reg_red)

Call:
lm(formula = CRP1 ~ SE + Leukocit + Trombocit + Glukoza + Urea + 
    Kreatinin + Kalij + eGFR + ALT + LDH1 + Bilirubin + HDL + 
    Trigliceridi + Trop1 + HSP90_1 + DaniUBolnici + Killip, data = df)

Residuals:
    Min      1Q  Median      3Q     Max 
-6.3157 -2.4521  0.0631  1.9349  7.5357 

Coefficients:
               Estimate Std. Error t value Pr(>|t|)    
(Intercept)   4.5019765  5.5143133   0.816 0.415965    
SE            0.0285435  0.0271895   1.050 0.296031    
Leukocit      0.5025351  0.1642444   3.060 0.002763 ** 
Trombocit     0.0083517  0.0083473   1.001 0.319175    
Glukoza      -0.2168022  0.4150065  -0.522 0.602401    
Urea          0.1309507  0.2678411   0.489 0.625843    
Kreatinin    -0.0105603  0.0215522  -0.490 0.625086    
Kalij        -0.1120215  0.9230531  -0.121 0.903620    
eGFR         -0.0544005  0.0190283  -2.859 0.005056 ** 
ALT          -0.0511410  0.0135566  -3.772 0.000258 ***
LDH1          0.0015478  0.0013610   1.137 0.257820    
Bilirubin    -0.0457922  0.0510682  -0.897 0.371775    
HDL          -0.4837145  1.0700588  -0.452 0.652096    
Trigliceridi  0.9054773  0.4282574   2.114 0.036666 *  
Trop1         0.0948041  0.0262222   3.615 0.000448 ***
HSP90_1      -0.0004647  0.0014706  -0.316 0.752602    
DaniUBolnici  0.0288543  0.0652117   0.442 0.658986    
Killip        0.5277039  0.8052825   0.655 0.513593    
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 3.358 on 114 degrees of freedom
Multiple R-squared:  0.4491,    Adjusted R-squared:  0.3669 
F-statistic: 5.467 on 17 and 114 DF,  p-value: 9.14e-09
# KORAK 4: VIF reducirani model
vif(model_reg_red)
          SE     Leukocit    Trombocit      Glukoza         Urea    Kreatinin 
    1.632119     3.098319     2.630266     1.134389     3.734346     3.112628 
       Kalij         eGFR          ALT         LDH1    Bilirubin          HDL 
    1.855483     3.392247     2.384180     2.883439     1.434336     1.374553 
Trigliceridi        Trop1      HSP90_1 DaniUBolnici       Killip 
    1.204096     1.447141     1.323247     1.453319     1.410174 
# KORAK 5: Normalnost reziduala
shapiro.test(residuals(model_reg_red))

    Shapiro-Wilk normality test

data:  residuals(model_reg_red)
W = 0.98349, p-value = 0.1103
# KORAK 6: Dijagnostički grafovi
par(mfrow = c(2,2))
plot(model_reg_red)

par(mfrow = c(1,1))

# KORAK 7: Forest plot koeficijenata
koef <- as.data.frame(confint(model_reg_red))
koef$Prediktor <- rownames(koef)
koef$Estimate <- coef(model_reg_red)
koef <- koef[koef$Prediktor != "(Intercept)", ]
koef$Znacajan <- ifelse(
  (koef$`2.5 %` > 0 & koef$`97.5 %` > 0) | 
  (koef$`2.5 %` < 0 & koef$`97.5 %` < 0), 
  "Značajan", "Nije značajan")

ggplot(koef, aes(x = reorder(Prediktor, Estimate), 
                 y = Estimate, color = Znacajan)) +
  geom_point(size = 3) +
  geom_errorbar(aes(ymin = `2.5 %`, ymax = `97.5 %`), width = 0.3) +
  geom_hline(yintercept = 0, linetype = "dashed", color = "gray") +
  scale_color_manual(values = c("Značajan" = "#E74C3C", 
                                "Nije značajan" = "#95A5A6")) +
  coord_flip() +
  labs(title = "Regresijski koeficijenti s 95% CI",
       x = "Prediktor", y = "Koeficijent (b)", color = "") +
  theme_minimal(base_size = 12)

Postupak:

U inicijalni model uključeni su svi potencijalni prediktori. Nakon provjere multikolinearnosti (VIF), iz modela su uklonjeni prediktori s VIF > 5 (Eritrociti, Hgb, Kolesterol, LDL, AST) i proveden je reducirani model.

Provjera pretpostavki:

1. Kolinearnost prediktora: VIF svih prediktora (nakon uklanjanja) < 5 → nema multikolinearnosti. U inicijalnom modelu uklonjeni su prediktori s VIF > 5 (Eritrociti, Hgb, Kolesterol, LDL, AST) koji su pokazivali visoku međusobnu korelaciju.

2. Normalnost reziduala*: Shapiro-Wilk test reziduala: W = 1; p = 0,1 → reziduali su normalno distribuirani. Q-Q plot potvrđuje da točke prate dijagonalnu liniju bez većih odstupanja.

3. Linearnost odnosa*: Residuals vs Fitted plot pokazuje nasumičan raspored točaka oko nule bez vidljivog obrasca → pretpostavka linearnosti je zadovoljena.

4. Jednakost varijanci reziduala*: Scale-Location plot pokazuje relativno ravnu crvenu liniju → varijanca reziduala je približno jednaka duž cijelog raspona predviđenih vrijednosti.

5. Utjecajne točke*: Residuals vs Leverage plot pokazuje da nema točaka izvan Cookove udaljenosti → nema problematičnih outliera koji bi narušavali model

*2.-5. točka - R automatski vizualno provjerava koristeći funkciju plot(model)

Ocjena modela:

Model: CRP1 ~ SE + Leukocit + Trombocit + Glukoza + Urea + Kreatinin + Kalij + eGFR + ALT + LDH1 + Bilirubin + HDL + Trigliceridi + Trop1 + HSP90_1 + DaniUBolnici + Killip

  • F(17, 114) = 5,47; p < 0,001 → model je statistički značajan

  • R² = 0,449 → model objašnjava 44,9% varijance CRP1

  • Adj. R² = 0,367 → nakon korekcije za broj prediktora, model objašnjava 36,7%

Zaključak:

Višestrukom regresijskom analizom identificirani su neovisni prediktori razine CRP-a. Na forest plotu regresijskih koeficijenata s 95% intervalima pouzdanosti crvenom bojom označeni su statistički značajni prediktori čiji intervali pouzdanosti ne prelaze nulu.

Značajni prediktori (p < 0,05):

Trop1: b = 0,095 ± 0,026 — Trop1 pozitivno korelira s CRP1; za jediničnu promjenu Trop1 promjena CRP1 iznosi 0,095 ± 0,026

Trop1: t(114) = 3,615; p < 0,001 — beta koeficijent Trop1 kao prediktora je visoko statistički značajan (potreba zadržavanja u modelu!) — Trop1 je značajno povezan s CRP1

ALT: b = -0,051 ± 0,014 — ALT negativno korelira s CRP1; za jediničnu promjenu ALT promjena CRP1 iznosi -0,051 ± 0,014

ALT: t(114) = -3,772; p < 0,001 — beta koeficijent ALT kao prediktora je visoko statistički značajan (potreba zadržavanja u modelu!) — ALT je značajno povezan s CRP1

Leukocit: b = 0,503 ± 0,164 — Leukocit pozitivno korelira s CRP1; za jediničnu promjenu Leukocita promjena CRP1 iznosi 0,503 ± 0,164

Leukocit: t(114) = 3,060; p = 0,003 — beta koeficijent Leukocita kao prediktora je statistički značajan (potreba zadržavanja u modelu!) — Leukocit je značajno povezan s CRP1

eGFR: b = -0,054 ± 0,019 — eGFR negativno korelira s CRP1; za jediničnu promjenu eGFR promjena CRP1 iznosi -0,054 ± 0,019

eGFR: t(114) = -2,859; p = 0,005 — beta koeficijent eGFR kao prediktora je statistički značajan (potreba zadržavanja u modelu!) — eGFR je značajno povezan s CRP1

Trigliceridi: b = 0,905 ± 0,428 — Trigliceridi pozitivno koreliraju s CRP1; za jediničnu promjenu Triglicerida promjena CRP1 iznosi 0,905 ± 0,428

Trigliceridi: t(114) = 2,114; p = 0,037 — beta koeficijent Triglicerida kao prediktora je statistički značajan (potreba zadržavanja u modelu!) — Trigliceridi su značajno povezani s CRP1

Ostali prediktori (SE, Trombocit, Glukoza, Urea, Kreatinin, Kalij, LDH1, Bilirubin, HDL, HSP90_1, DaniUBolnici, Killip) nisu se pokazali statistički značajnim neovisnim prediktorima CRP-a.

Model je statistički značajan (F(17, 114) = 5,47; p < 0,001) i objašnjava 44,9% varijance CRP-a (R² = 0,449; Adj. R² = 0,367), uz zadovoljene pretpostavke normalnosti reziduala i odsutnost multikolinearnosti. 



2.dio: Logistička regresija 
Napraviti logističku regresiju za samostalno odabrani primjer iz baze i interpretirati rezultate. Ocijenite model.

Zavisna varijabla: Spol (0 = F, 1 = M)

Nezavisna varijabla: Hemoglobin

Istraživačko pitanje:

Postoji li statistički značajna povezanost između razine hemoglobina i spola ispitanika?

H₀: Ne postoji statistički značajna povezanost između razine hemoglobina i spola ispitanika — razina hemoglobina nije značajan prediktor spola (b = 0)

H₁: Postoji statistički značajna povezanost između razine hemoglobina i spola ispitanika — razina hemoglobina je značajan prediktor spola (b ≠ 0)

# ================================================================
# 2. DIO — LOGISTIČKA REGRESIJA: SPOL ~ Hgb
# ================================================================

# SPOL kao binarna varijabla (M=1, F=0)
df$SPOL_bin <- ifelse(df$SPOL == "M", 1, 0)

# Model
model_null <- glm(SPOL_bin ~ 1, data = df, family = binomial)
model_log <- glm(SPOL_bin ~ Hgb, data = df, family = binomial(link = "logit"))
summary(model_log)

Call:
glm(formula = SPOL_bin ~ Hgb, family = binomial(link = "logit"), 
    data = df)

Coefficients:
             Estimate Std. Error z value Pr(>|z|)    
(Intercept) -10.59764    2.48918  -4.257 2.07e-05 ***
Hgb           0.08830    0.01937   4.560 5.12e-06 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 158.46  on 131  degrees of freedom
Residual deviance: 129.59  on 130  degrees of freedom
AIC: 133.59

Number of Fisher Scoring iterations: 5
# OR s 95% CI
exp(cbind(OR = coef(model_log), confint(model_log)))
Waiting for profiling to be done...
                      OR        2.5 %      97.5 %
(Intercept) 2.497482e-05 1.289096e-07 0.002407644
Hgb         1.092315e+00 1.054383e+00 1.138214037
# -2 Log likelihood
cat("-2 Log likelihood (null)  =", round(-2 * logLik(model_null), 3), "\n")
-2 Log likelihood (null)  = 158.464 
cat("-2 Log likelihood (model) =", round(-2 * logLik(model_log), 3), "\n")
-2 Log likelihood (model) = 129.594 
# Hi-kvadrat test (omnibus)
cat("\n--- Hi-kvadrat test ---\n")

--- Hi-kvadrat test ---
hi_kv <- model_null$deviance - model_log$deviance
df_hi <- model_null$df.residual - model_log$df.residual
p_hi <- pchisq(hi_kv, df = df_hi, lower.tail = FALSE)
cat("χ²(", df_hi, ") =", round(hi_kv, 3), "| p =", round(p_hi, 4), "\n")
χ²( 1 ) = 28.87 | p = 0 
# Logistička krivulja
b0 <- round(coef(model_log)[1], 3)
b1 <- round(coef(model_log)[2], 3)
hgb_seq <- seq(min(df$Hgb), max(df$Hgb), length.out = 300)
pred_curve <- predict(model_log, 
                      newdata = data.frame(Hgb = hgb_seq), 
                      type = "response")
curve_df <- data.frame(Hgb = hgb_seq, Vjerojatnost = pred_curve)

ggplot() +
  geom_point(data = df,
             aes(x = Hgb, y = SPOL_bin),
             color = "#2E86C1", alpha = 0.5, size = 2) +
  geom_line(data = curve_df,
            aes(x = Hgb, y = Vjerojatnost),
            color = "#E74C3C", linewidth = 1.2) +
  geom_hline(yintercept = 0.5, linetype = "dashed",
             color = "gray40", linewidth = 0.8) +
  annotate("text", x = max(df$Hgb) * 0.95, y = 0.53,
           label = "cut-off = 0.5", color = "gray40", size = 3.5) +
  labs(title = "Model: Logistička regresija (logit)",
       subtitle = paste0("y = exp(", b0, " + (", b1, ")*x) / (1 + exp(", b0, " + (", b1, ")*x))"),
       x = "Hemoglobin (Hgb)",
       y = "Vjerojatnost (SPOL = M)") +
  theme_minimal(base_size = 12)

Rezultati:

  • Hgb (b = 0,088; p < 0,001) → statistički značajan prediktor spola

  • OR = 1,092 (95% CI: 1,050–1,138) → svaki porast Hgb za 1 g/L povećava šanse da je ispitanik muškog spola za 9,2%

Ocjena modela:

-2 Log likelihood:

  • Null model: 158,46 (model bez ijednog prediktora; nasumično “pogađanje”)

  • Model s Hgb: 129,59

  • Smanjenje od 28,87 → model s prediktorom bolje pristaje podacima od null modela

Hi-kvadrat test:

  • χ²(1) = 28,9; p < 0,001 → model je statistički značajan u cjelini — Hgb značajno poboljšava predviđanje spola u odnosu na model bez prediktora

Zaključak:

Hemoglobin je statistički značajan prediktor spola (OR = 1,092; p < 0,001). Model je statistički značajan u cjelini (χ²(1) = 28,9; p < 0,001), a smanjenje -2LL s 158,46 na 129,59 potvrđuje da prediktor značajno poboljšava prilagodbu modela. 



3.dio: ROC analiza
Napraviti ROC analizu za samostalno odabrani primjer iz baze i interpretirati rezultate.

Zavisna varijabla: Spol (0 = F, 1 = M)

Nezavisna varijabla: Hemoglobin

Istraživačko pitanje:

Kolika je diskriminacijska sposobnost hemoglobina (Hgb) u razlikovanju muškog od ženskog spola u ispitivanoj skupini bolesnika?

H₀: AUC = 0,5 → hemoglobin nema diskriminacijsku sposobnost u razlikovanju muškog od ženskog spola (nije bolji od slučajnog pogađanja)

H₁: AUC > 0,5 → hemoglobin ima statistički značajnu diskriminacijsku sposobnost u razlikovanju muškog od ženskog spola

# ================================================================
# 3. DIO — ROC ANALIZA: SPOL ~ Hgb
# ================================================================

# ROC objekt
roc_obj <- roc(df$SPOL_bin, df$Hgb)
Setting levels: control = 0, case = 1
Setting direction: controls < cases
# AUC s 95% CI
cat("AUC =", round(auc(roc_obj), 3), "\n")
AUC = 0.774 
print(ci.auc(roc_obj))
95% CI: 0.6878-0.8598 (DeLong)
# Optimalni cut-off (Youden indeks - maksimizira zbroj senzitivnosti i specifičnosti)
osjetljivosti <- roc_obj$sensitivities
specificnosti <- roc_obj$specificities
youden <- osjetljivosti + specificnosti - 1
best_idx <- which.max(youden)
cat("\nOptimalni cut-off =", round(roc_obj$thresholds[best_idx], 1), "\n")

Optimalni cut-off = 126.5 
cat("Osjetljivosti=", round(osjetljivosti[best_idx] * 100, 1), "%\n")
Osjetljivosti= 80.9 %
cat("Specifičnost =", round(specificnosti[best_idx] * 100, 1), "%\n")
Specifičnost = 63.2 %
# Koordinate optimalne točke
best_x <- 1 - specificnosti[best_idx]
best_y <- osjetljivosti[best_idx]

# ROC krivulja
roc_df <- data.frame(
  Specifičnost = 1 - specificnosti,
  Osjetljivost = osjetljivosti
)
# 95% CI za osjetljivost i specifičnost
osjetljivost <- 0.809
specificnost <- 0.632
n_pozitivni <- 94  # muškarci
n_negativni <- 38  # žene

# CI za osjetljivost
ci_osj <- prop.test(round(osjetljivost * n_pozitivni), 
                     n_pozitivni, conf.level = 0.95)
cat("Osjetljivost 95% CI: (", 
    round(ci_osj$conf.int[1] * 100, 1), "% -",
    round(ci_osj$conf.int[2] * 100, 1), "%)\n")
Osjetljivost 95% CI: ( 71.2 % - 88 %)
# CI za specifičnost
ci_spec <- prop.test(round(specificnost * n_negativni), 
                     n_negativni, conf.level = 0.95)
cat("Specifičnost 95% CI: (", 
    round(ci_spec$conf.int[1] * 100, 1), "% -",
    round(ci_spec$conf.int[2] * 100, 1), "%)\n")
Specifičnost 95% CI: ( 46 % - 77.7 %)
# Pozitivni LR (+LR)
LR_plus <- osjetljivost / (1 - specificnost)
cat("+LR =", round(LR_plus, 3), "\n")
+LR = 2.198 
# Negativni LR (-LR)
LR_minus <- (1 - osjetljivost) / specificnost
cat("-LR =", round(LR_minus, 3), "\n")
-LR = 0.302 
# 95% CI za +LR i -LR (log metoda)
osjetljivost <- 0.809
specificnost <- 0.632
n_pozitivni <- 94
n_negativni <- 38

# +LR
LR_plus <- osjetljivost / (1 - specificnost)

SE_log_LR_plus <- sqrt((1 - osjetljivost) / (osjetljivost * n_pozitivni) + 
                        specificnost / ((1 - specificnost) * n_negativni))

CI_low_plus <- exp(log(LR_plus) - 1.96 * SE_log_LR_plus)
CI_high_plus <- exp(log(LR_plus) + 1.96 * SE_log_LR_plus)

cat("+LR =", round(LR_plus, 3), 
    "| 95% CI: (", round(CI_low_plus, 3), "-", round(CI_high_plus, 3), ")\n")
+LR = 2.198 | 95% CI: ( 1.433 - 3.373 )
# -LR
LR_minus <- (1 - osjetljivost) / specificnost

SE_log_LR_minus <- sqrt(osjetljivost / ((1 - osjetljivost) * n_pozitivni) + 
                         (1 - specificnost) / (specificnost * n_negativni))

CI_low_minus <- exp(log(LR_minus) - 1.96 * SE_log_LR_minus)
CI_high_minus <- exp(log(LR_minus) + 1.96 * SE_log_LR_minus)

cat("-LR =", round(LR_minus, 3), 
    "| 95% CI: (", round(CI_low_minus, 3), "-", round(CI_high_minus, 3), ")\n")
-LR = 0.302 | 95% CI: ( 0.187 - 0.489 )
ggplot(roc_df, aes(x = Specifičnost, y = Osjetljivost)) +
  geom_line(color = "#2E86C1", linewidth = 1.2) +
  geom_abline(intercept = 0, slope = 1,
              linetype = "dashed", color = "gray40") +
  annotate("text", x = 0.7, y = 0.2,
           label = paste0("AUC = ", round(auc(roc_obj), 3)),
           size = 5, color = "#2E86C1", fontface = "bold") +
  annotate("point", x = best_x, y = best_y,
           color = "#E74C3C", size = 4) +
  annotate("text",
           x = best_x + 0.08,
           y = best_y - 0.05,
           label = paste0("cut-off = ", round(roc_obj$thresholds[best_idx], 1)),
           size = 3.5, color = "#E74C3C") +
  labs(title = "ROC krivulja — SPOL ~ Hgb",
       subtitle = paste0("AUC = ", round(auc(roc_obj), 3),
                         " (95% CI: ", round(ci.auc(roc_obj)[1], 3),
                         " – ", round(ci.auc(roc_obj)[3], 3), ")"),
       x = "1 - Specifičnost (Lažno pozitivni)",
       y = "  Osjetljivost (Stvarno pozitivni)") +
  theme_minimal(base_size = 12)

Rezultati:

Mjera Vrijednost
AUC 0,774
95% CI (DeLong) 0,688 – 0,860
Optimalni cut-off (Youden) 126 g/L
Osjetljivost 80,9%
Specifičnost 63,2%

Kriterij > 126 g/L — za vrijednosti Hgb > 126 g/L ROC analiza predlaže svrstavanje ispitanika u skupinu M (muški), ostale u skupinu F (ženski).

Osjetljivost = 80,9% (95% CI: 71,2% – 88,0%) — 80,9% je udio stvarno pozitivnih (sa Hgb > 126 g/L) u skupini M

Specifičnost = 63,2% (95% CI: 46,0% – 77,7%) — 63,2% je udio stvarno negativnih (sa Hgb ≤ 126 g/L) u skupini F

+LR = 2,20 (95% CI: 1,433 – 3,373) — pozitivna prediktivna vrijednost — 2,20 puta su veći izgledi da ćemo pozitivan rezultat (Hgb > 126 g/L) naći u skupini M u odnosu na izglede da ga nađemo u skupini F

-LR = 0,302 (95% CI: 0,187 – 0,489) ≅ 1/3,31 — negativna prediktivna vrijednost — izgledi da negativan rezultat (Hgb < 126 g/L) nađemo u skupini M u odnosu na izgled da ga nađemo u skupini F su 1:3,31

Zaključak:

ROC analiza pokazala je da hemoglobin ima prihvatljivu diskriminacijsku sposobnost u razlikovanju muškog od ženskog spola (AUC = 0,774; 95% CI: 0,688–0,860). Interval pouzdanosti ne uključuje 0,5, što potvrđuje da je diskriminacija statistički značajno bolja od slučajnog pogađanja.

Pri optimalnom cut-offu od 126 g/L (određenom Youden indeksom) model postiže:

  • Osjetljivost = 80,9%

  • Specifičnost = 63,2%