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.
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
GesundCRP: normal oder erhoehtFEV1_FVC: numerischBetrachten 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?
Import:
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.
## 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.
Sie können die Werte manuell anhand der 2x2 Tabelle berechnen oder
mit Hilfe der Funktion epi.tests aus dem Paket
epiR.
Interpretieren Sie die Werte.
Wie wahrscheinlich ist es, dass Herr M. and COPD leidet?
Wie könnte man die diagnostische Sicherheit erhöhen?
## 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]
Sp = 0.79, 95% CI = [0.66, 0.89]
PPV = 0.81, 95% CI = [0.69, 0.90]
NPV = 0.69, 95% CI = [0.57, 0.80]
LR+ = 3.41, 95% CI = [2.02, 5.76]
LR− = 0.36, 95% CI = [0.24, 0.53]
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.
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.
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".
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
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
## 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
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.
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.