Wir betrachten folgende Situation:

Herr M., 62 Jahre, ehemaliger Bauarbeiter.
Anamnese: 40 Packyears, seit 5 Jahren Nichtraucher. Seit einigen Monaten zunehmende Atemnot beim Treppensteigen, produktiver Husten vor allem morgens.
Klinischer Befund: Auskultatorisch leicht verlängertes Exspirium, vereinzelte Giemen, keine Rasselgeräusche.
Hypothese: COPD
Test 1: Es wird das CRP (C-reaktives Protein) analysiert, der Wert ist erhöt (damit der Test positiv)
Test 2: Als zweiter Test steht die Spirometrie zur Verfügung. Der FEV1/FVC-Wert beträgt 0.65.

In der Folge werden die Inhalte aus der Vorlesung praktisch angewendet. Sie werden anhnad vorgegebener Werte die Testgüte bestimmen und eine Testlogik entwickeln und diese Kenntnissse dann auf diesen konkreten Fall anwenden.



Übung 1

Wir verwenden den Datensatz df-copd.RData. Importieren Sie diesen in R mit load("df-copd.RData"). Faktoren sind so automatisch korrekt hinterlegt.

Der Datensatz beinhaltet folgende Variablen:

  • Status: COPD oder Gesund
  • CRP: normal oder erhoeht
  • FEV1_FVC: numerisch

Aufgabe

Betrachten Sie zunächst die Variablen Status und CRP. Wie hoch ist die Prävalenz von COPD? Bei wie vielen Personen ist der CRP-Wert erhöht?



Lösung

Import:

load("../data/df-copd.RData")

Wir betrachten die Daten in einer Kreuztabell mithilfe der Funktion ctable aus dem Paket summarytools (schon gebraucht in führeren Übungen). Andere Lösungswege sind durchaus möglich.

library(summarytools)
ctable(df.copd$CRP, df.copd$Status, prop = "t")
## Cross-Tabulation, Total Proportions  
## CRP * Status  
## Data Frame: df.copd  
## 
## --------- -------- ------------ ------------ --------------
##             Status         COPD       Gesund          Total
##       CRP                                                  
##   erhoeht            51 (39.8%)   12 ( 9.4%)    63 ( 49.2%)
##    normal            20 (15.6%)   45 (35.2%)    65 ( 50.8%)
##     Total            71 (55.5%)   57 (44.5%)   128 (100.0%)
## --------- -------- ------------ ------------ --------------

Es liegt eine Prävalenz von 55.5% vor. Fast bei der Hälfte aller Personen ist der Test positiv, es gibt aber falsch-negative sowie falsch-positive Resultate.


Übung 2

Aufgabe

  1. Berechnen Sie folgende Kennwerte, basierend auf den Daten:
  • \(Sn\) & \(Sp\)
  • \(PPV\) & \(NPV\)
  • \(LR^+\) & \(LR^-\)

Sie können die Werte manuell anhand der 2x2 Tabelle berechnen oder mit Hilfe der Funktion epi.tests aus dem Paket epiR.

  1. Interpretieren Sie die Werte.

  2. Wie wahrscheinlich ist es, dass Herr M. and COPD leidet?

  3. Wie könnte man die diagnostische Sicherheit erhöhen?



Lösung

library(epiR)
tab <- table(df.copd$CRP, df.copd$Status)
epi.tests(tab)
##           Outcome +    Outcome -      Total
## Test +           51           12         63
## Test -           20           45         65
## Total            71           57        128
## 
## Point estimates and 95% CIs:
## --------------------------------------------------------------
## Apparent prevalence *                  0.49 (0.40, 0.58)
## True prevalence *                      0.55 (0.46, 0.64)
## Sensitivity *                          0.72 (0.60, 0.82)
## Specificity *                          0.79 (0.66, 0.89)
## Positive predictive value *            0.81 (0.69, 0.90)
## Negative predictive value *            0.69 (0.57, 0.80)
## Positive likelihood ratio              3.41 (2.02, 5.76)
## Negative likelihood ratio              0.36 (0.24, 0.53)
## False T+ proportion for true D- *      0.21 (0.11, 0.34)
## False T- proportion for true D+ *      0.28 (0.18, 0.40)
## False T+ proportion for T+ *           0.19 (0.10, 0.31)
## False T- proportion for T- *           0.31 (0.20, 0.43)
## Correctly classified proportion *      0.75 (0.67, 0.82)
## --------------------------------------------------------------
## * Exact CIs

Sn = 0.72, 95% CI = [0.60, 0.82]

  • Anteil der tatsächlich Kranken (COPD-Patienten), die vom Test korrekt als krank erkannt werden.
  • 72 % der Personen mit COPD werden korrekt durch CRP als positiv erkannt.
  • Der Test verpasst etwa 28 % der tatsächlichen COPD-Fälle (falsch negativ).

Sp = 0.79, 95% CI = [0.66, 0.89]

  • Anteil der tatsächlich Gesunden, die korrekt als gesund erkannt werden.
  • 79 % der Personen ohne COPD werden korrekt als negativ eingestuft.
  • Es gibt etwa 21 % falsch positive Ergebnisse.

PPV = 0.81, 95% CI = [0.69, 0.90]

  • Wahrscheinlichkeit, dass eine Person tatsächlich COPD hat, wenn der Test positiv ist.
  • Wenn der CRP-Test positiv ist, liegt bei 81 % Wahrscheinlichkeit eine COPD vor.
  • Positiv getestete Patienten haben eine relativ hohe Chance, wirklich krank zu sein, jedoch ist rund jede 5. Person falsch-positiv.

NPV = 0.69, 95% CI = [0.57, 0.80]

  • Wahrscheinlichkeit, dass eine Person tatsächlich gesund ist, wenn der Test negativ ist.
  • Ein negativer Test bedeutet 69 % Wahrscheinlichkeit, dass keine COPD vorliegt.
  • Ein negatives Ergebnis schliesst COPD nicht sicher aus – es gibt noch 31 % falsch negative Fälle.

LR+ = 3.41, 95% CI = [2.02, 5.76]

  • Verhältnis der Wahrscheinlichkeit eines positiven Tests bei Kranken zur Wahrscheinlichkeit eines positiven Tests bei Gesunden.
  • 3.41 bedeutet, dass ein positiver Test 3.4-mal wahrscheinlicher bei COPD-Patienten auftritt als bei Gesunden. Das ist kein “starker Beweis”.

LR− = 0.36, 95% CI = [0.24, 0.53]

  • Verhältnis der Wahrscheinlichkeit eines negativen Tests bei Kranken zur Wahrscheinlichkeit eines negativen Tests bei Gesunden.
  • 0.36 bedeutet, dass ein negativer Test die Wahrscheinlichkeit einer COPD moderat verringert, aber nicht sicher ausschliesst.

Die geschätzte Wahrscheinlichkeit, dass Herr M. an COPD leidet ist 81%. Allerdings ist das 95% CI relativ breit (eine Wahrscheinlichkeit von 70% ist ebenfalls plausibel).

Die diagnostische Sicherheit kann erhöt werden, wenn ein oder mehrere zusätzliche Tests herangezogen werden.



Übung 3

Wir betrachten nun den zweiten Test; eine Spirometrie. Dort werden verschiedene Parameter erfasst, unter anderem die Werte FEV1 und FVC. Der Quotient aus den beiden Werten gilt als guter Prädiktor für eine COPD.

Aufgabe

Verwenden Sie die Variablen Status und FEV1_FVC. Verwenden Sie die Funktionen roc, auc und coords aus dem Paket pROC. Achtung: Die Variable Stauts hat die Levels COPD und Gesund. Damit COPD zu 1 wird und Gesund zu 0, können Sie diesen Code verwenden: df.copd$Status == "COPD".

  1. Führen Sie eine ROC-Analyse durch und bestimmen Sie die AUC sowie einen optimalen Cut-off unter Verwendung des Youden-Index.
  2. Interpretieren Sie.
  3. Stellen Sie die Kurve graphisch dar.



Lösung

library(pROC)
roc.obj <- roc(df.copd$Status == "COPD", df.copd$FEV1_FVC) # 0 = Gesund, 1 = Krank

# AUC berechnen
auc(roc.obj)
## Area under the curve: 0.9486
# Optimaler Cut-off (Youden)
coords(roc.obj, "best", ret=c("threshold","sensitivity","specificity"))
##   threshold sensitivity specificity
## 1     0.735    0.943662   0.8421053
# ROC-Curve
plot(roc.obj)

Interpretation:

Die AUC beträgt 0.95, was ein guter Wert ist. Als Cut-off schlägt uns das Modell 0.735 vor (ist der Wert kleiner, ist der Test positiv), was in einer \(Sn\) von 94% und einer \(Sp\) von 84% resultiert. Die Werte sind besser als beim ersten Test. Laut den offiziellen GOLD-Kriterien für die Diagnose von COPD liegt der Cut-off bei 0.7. Wir sind also nicht so weit daneben (GOLD-Criteria).

Wir können die Werte anhand der 2x2 Tabelle überprüfen:

df.copd$FEV1_FVC_BIN <- ifelse(df.copd$FEV1_FVC < 0.735, "positiv", "negativ")
df.copd$FEV1_FVC_BIN <- factor(df.copd$FEV1_FVC_BIN, levels = c("positiv", "negativ"))
tab <- table(df.copd$FEV1_FVC_BIN, df.copd$Status)
tab
##          
##           COPD Gesund
##   positiv   67      9
##   negativ    4     48
epi.tests(tab)
##           Outcome +    Outcome -      Total
## Test +           67            9         76
## Test -            4           48         52
## Total            71           57        128
## 
## Point estimates and 95% CIs:
## --------------------------------------------------------------
## Apparent prevalence *                  0.59 (0.50, 0.68)
## True prevalence *                      0.55 (0.46, 0.64)
## Sensitivity *                          0.94 (0.86, 0.98)
## Specificity *                          0.84 (0.72, 0.93)
## Positive predictive value *            0.88 (0.79, 0.94)
## Negative predictive value *            0.92 (0.81, 0.98)
## Positive likelihood ratio              5.98 (3.27, 10.91)
## Negative likelihood ratio              0.07 (0.03, 0.17)
## False T+ proportion for true D- *      0.16 (0.07, 0.28)
## False T- proportion for true D+ *      0.06 (0.02, 0.14)
## False T+ proportion for T+ *           0.12 (0.06, 0.21)
## False T- proportion for T- *           0.08 (0.02, 0.19)
## Correctly classified proportion *      0.90 (0.83, 0.94)
## --------------------------------------------------------------
## * Exact CIs



Übung 4

Aufgabe

Als letztes betrachten wir das Gesamtergebnis, wenn wir die beiden Tests kombinieren. Wir gehen dabei davon aus, dass die beiden Tests unabhängig sind von einander.

  1. Berechnen sie die Net-\(Sn\) und Net-\(Sp\) für den Fall, wenn die Tests parallel angewendet werden (einer der beiden muss positiv sein, dann ist das Gesamtresultat positiv).
  2. Wie gross ist bei einer parallelen Testlogik die Wahrscheinlichkeit, dass bei Herr M. COPD vorliegt?
  3. Wie verändern sich die Werte aus 1. und 2. bei einer sequenziellen Testlogik?
  4. Ziehen Sie ein Fazit dieser Übung.



Lösung

Parallele Testung

Bei zwei unabhängigen Tests A & B gilt bei paralleler Anwendung:

\[ Sn_{parallel}=1−(1−Sn_A)(1−Sn_B) \]

und

\[ Sp_{parallel} = Sp_A Sp_B. \]

Wir erhalten somit

\[ Sn_{parallel}=1−(1−0.72)(1−0.94) = 0.98 \]

und

\[ Sp_{parallel} = 0.79 \times 0.84 = 0.66. \]

Wir könnten das auch anhand der Daten überprüfen, kommen aber auf leicht andere Resultate, weil die Tests bei den hier verwendeten Daten nicht ganz unabhänig sind:

df.copd$tot_parallel <- ifelse(df.copd$CRP == "erhoeht" | df.copd$FEV1_FVC < 0.735, "positiv", "negativ")
df.copd$tot_parallel <- factor(df.copd$tot_parallel, levels = c("positiv", "negativ"))
tab <- table(df.copd$tot_parallel, df.copd$Status)
epi.tests(tab)
##           Outcome +    Outcome -      Total
## Test +           70           17         87
## Test -            1           40         41
## Total            71           57        128
## 
## Point estimates and 95% CIs:
## --------------------------------------------------------------
## Apparent prevalence *                  0.68 (0.59, 0.76)
## True prevalence *                      0.55 (0.46, 0.64)
## Sensitivity *                          0.99 (0.92, 1.00)
## Specificity *                          0.70 (0.57, 0.82)
## Positive predictive value *            0.80 (0.71, 0.88)
## Negative predictive value *            0.98 (0.87, 1.00)
## Positive likelihood ratio              3.31 (2.22, 4.93)
## Negative likelihood ratio              0.02 (0.00, 0.14)
## False T+ proportion for true D- *      0.30 (0.18, 0.43)
## False T- proportion for true D+ *      0.01 (0.00, 0.08)
## False T+ proportion for T+ *           0.20 (0.12, 0.29)
## False T- proportion for T- *           0.02 (0.00, 0.13)
## Correctly classified proportion *      0.86 (0.79, 0.91)
## --------------------------------------------------------------
## * Exact CIs

Wir sehen oben bereits den \(PPV\), also die Wahrscheinlichkeit dafür, dass Herr M. bei einer parallelen Testlogik COPD hat (80%).

Wir können dies aber auch manuell berechnen, wenn wir die Prävalenz als Vortestwahrscheinlichkeit betrachten. Zuerst berechnen wir die \(LR^+\)

\[ LR⁺ = = \frac{\text{Sensitivität}}{1 - \text{Spezifität}} = \frac{0.98}{1-0.66} = 2.88. \]

Danach können wir via Odds die Nachtestwahrscheinlichkeit berechnen:

\[ Odds(\text{Posterior}) = \frac{0.55}{1-0.55} * 2.88 = 3.52. \] Aus dieser Odds können wir die Wahrscheinlichkeit zurückgewinnen:

\[ PPV = \frac{3.52}{1+3.52} = 0.78. \]


Sequenzielle Testung

Bei zwei unabhängigen Tests A & B gilt bei sequenzieller Anwendung:

\[ Sn_{seq}=Sn_A Sn_B \]

und

\[ Sp_{seq} = 1-(1-Sp_A)(1-Sp_B). \]

Wir erhalten somit

\[ Sn_{seq}=0.72 \times 0.94 = 0.71 \]

und

\[ Sp_{seq} = 1-(1-0.79) (1-0.84) = 0.97. \]

Wir könnten das auch anhand der Daten überprüfen, kommen aber auf leicht andere Resultate, weil die Tests bei den hier verwendeten Daten nicht ganz unabhänig sind:

df.copd$tot_seq <- ifelse(df.copd$CRP == "erhoeht" & df.copd$FEV1_FVC < 0.735, "positiv", "negativ")
df.copd$tot_seq <- factor(df.copd$tot_seq, levels = c("positiv", "negativ"))
tab <- table(df.copd$tot_seq, df.copd$Status)
epi.tests(tab)
##           Outcome +    Outcome -      Total
## Test +           48            4         52
## Test -           23           53         76
## Total            71           57        128
## 
## Point estimates and 95% CIs:
## --------------------------------------------------------------
## Apparent prevalence *                  0.41 (0.32, 0.50)
## True prevalence *                      0.55 (0.46, 0.64)
## Sensitivity *                          0.68 (0.55, 0.78)
## Specificity *                          0.93 (0.83, 0.98)
## Positive predictive value *            0.92 (0.81, 0.98)
## Negative predictive value *            0.70 (0.58, 0.80)
## Positive likelihood ratio              9.63 (3.69, 25.13)
## Negative likelihood ratio              0.35 (0.25, 0.49)
## False T+ proportion for true D- *      0.07 (0.02, 0.17)
## False T- proportion for true D+ *      0.32 (0.22, 0.45)
## False T+ proportion for T+ *           0.08 (0.02, 0.19)
## False T- proportion for T- *           0.30 (0.20, 0.42)
## Correctly classified proportion *      0.79 (0.71, 0.86)
## --------------------------------------------------------------
## * Exact CIs

Wir sehen oben bereits den \(PPV\), also die Wahrscheinlichkeit dafür, dass Herr M. bei einer sequenziellen Testlogik COPD hat (92%).

Wir können dies aber auch manuell berechnen, wenn wir die Prävalenz als Vortestwahrscheinlichkeit betrachten. Zuerst berechnen wir die \(LR^+\)

\[ LR⁺ = = \frac{\text{Sensitivität}}{1 - \text{Spezifität}} = \frac{0.71}{1-0.97} = 23.67. \]

Danach können wir via Odds die Nachtestwahrscheinlichkeit berechnen:

\[ Odds(\text{Posterior}) = \frac{0.55}{1-0.55} * 23.67 = 28.93. \] Aus dieser Odds können wir die Wahrscheinlichkeit zurückgewinnen:

\[ PPV = \frac{28.93}{1+28.93} = 0.97. \]

Fazit

Wie erwartet, steigt bei paralleler Testlogit \(Sn\) und \(Sp\) nimmt ab. Die SpIn & SnOut Regel weist bereits darauf hin, das dies ungünstig ist, um eine Diagnose sicher zu stellen. Wir sehen das auch am PPV bei paralleler Testanwendung: Dieser ist nicht besser als nach dem ersten Test alleine. Eine parallele Testlogik macht in erster Linie dann Sinn, wenn man auf keinen Fall etwas verpassen möchte und falsch-positive Ergebnisse keine schlimmen Konsequenzen haben (z. B. Schwangerschaftsdiabetes). Mit einer parallelen Testlogik können wir bei Herr. M. die Diagnose nicht sicher stellen.

Bei der sequenziellen Testung ist es genau umgekehrt: \(Sn\) sinkt und \(Sp\) stiegt. Als folge steigt der PPV, so dass wir bei dieser Testlogikt die Diagnose bei Herr M. relativ sicher stellen können. Diese Testlogik macht also Sinn, wenn wir mit grosser Sicherheit eine Krankheit einschliessen wollen.

Es fällt zudem auf, das die \(LR^+\) bei sequenzielle Anwendung sehr hoch ist.

Es ist ein grundlegendes diagnostisches Prinzip in der Medizin, dass zuerst ein sensitives Screening durchgeführt wird (nichts verpassen), gefolgt von einem spezifischeren Test zur Besätigung.