Für diese Übung brauchst du den Datensatz
blood-pressure.csv. Den Datensatz findest du auf Moodle.
Der Datensatz beinhaltet Informationen zu:
drug)Lade den Datensatz herunter und lese ihn in R ein.
Prüfe, ob der Datensatz richtig eingelesen wurde (z.B. durch
str() oder visuelle Überprüfung).
Gibt es im Datensatz fehlende Werte (NA’s)? Tipp:
is.na() oder summary()
Den Datensatz kannst du mit der import() Funktion aus
dem Package rio importieren. Achte darauf, dass die Working
Directory richtig eingestellt ist.
## 'data.frame': 100 obs. of 9 variables:
## $ pid : int 1 2 3 4 5 6 7 8 9 10 ...
## $ gender: chr "female" NA "male" "female" ...
## $ drug : chr "yes" "no" "no" "yes" ...
## $ age : num NA 56.5 45.9 64 58 52.9 77.8 56.9 49.9 65.3 ...
## $ weight: int 66 82 65 59 55 75 84 68 66 68 ...
## $ height: int 173 NA 165 160 174 182 169 177 169 175 ...
## $ bmi : num 22.1 NA 23.9 23 18.2 22.6 29.4 21.7 23.1 22.2 ...
## $ bp1 : int 129 122 109 126 NA 106 128 144 118 132 ...
## $ bp2 : int 123 122 105 116 139 109 133 133 117 120 ...
Fehlende Werte
Mit der is.na() Funktion kann für jede Zelle im
Datensatz abgefragt werden, ob es sich um einen NA handelt.
Falls ja, resultiert ein TRUE, falls nein ein
FALSE. In der Computersprache entspricht ein
TRUE dem Wert 1, ein FALSE dem Wert 0. Wenn
man mit sum() alle TRUEs zusammenzählt, erhält
man die Anzahl fehlender Werte (in diesem Fall 9).
## [1] 9
Man kann auch die summary() Funktion verwenden, dann
werden die NAs pro Variable angezeigt.
Achtung: bei Character-Variablen funktioniert das nicht
→ Ein weiterer Grund, warum man solche Variablen in Faktoren umwandeln
sollte.
Ohne Umwandlung:
## pid gender drug age
## Min. : 1.00 Length:100 Length:100 Min. :28.90
## 1st Qu.: 25.75 Class :character Class :character 1st Qu.:45.40
## Median : 50.50 Mode :character Mode :character Median :51.40
## Mean : 50.50 Mean :51.23
## 3rd Qu.: 75.25 3rd Qu.:56.10
## Max. :100.00 Max. :79.00
## NA's :1
## weight height bmi bp1
## Min. :53.00 Min. :154.0 Min. :17.20 Min. : 97.0
## 1st Qu.:63.75 1st Qu.:164.0 1st Qu.:23.10 1st Qu.:115.5
## Median :68.50 Median :169.0 Median :24.20 Median :121.0
## Mean :69.76 Mean :169.3 Mean :24.23 Mean :121.8
## 3rd Qu.:76.00 3rd Qu.:174.5 3rd Qu.:25.10 3rd Qu.:128.0
## Max. :91.00 Max. :188.0 Max. :32.50 Max. :155.0
## NA's :1 NA's :1 NA's :1
## bp2
## Min. : 92.0
## 1st Qu.:111.0
## Median :119.0
## Mean :119.8
## 3rd Qu.:128.0
## Max. :160.0
## NA's :2
Mit Umwandlung:
## pid gender drug age weight
## Min. : 1.00 female:53 no :50 Min. :28.90 Min. :53.00
## 1st Qu.: 25.75 male :46 yes :48 1st Qu.:45.40 1st Qu.:63.75
## Median : 50.50 NA's : 1 NA's: 2 Median :51.40 Median :68.50
## Mean : 50.50 Mean :51.23 Mean :69.76
## 3rd Qu.: 75.25 3rd Qu.:56.10 3rd Qu.:76.00
## Max. :100.00 Max. :79.00 Max. :91.00
## NA's :1
## height bmi bp1 bp2
## Min. :154.0 Min. :17.20 Min. : 97.0 Min. : 92.0
## 1st Qu.:164.0 1st Qu.:23.10 1st Qu.:115.5 1st Qu.:111.0
## Median :169.0 Median :24.20 Median :121.0 Median :119.0
## Mean :169.3 Mean :24.23 Mean :121.8 Mean :119.8
## 3rd Qu.:174.5 3rd Qu.:25.10 3rd Qu.:128.0 3rd Qu.:128.0
## Max. :188.0 Max. :32.50 Max. :155.0 Max. :160.0
## NA's :1 NA's :1 NA's :1 NA's :2
stringsAsFactors=TRUE beim Einlesen: Wenn man in
import() dieses Argument setzt (default ist FALSE), muss
man Character-Variablen nicht mehr explizit als Faktoren
deklarieren:
## 'data.frame': 100 obs. of 9 variables:
## $ pid : int 1 2 3 4 5 6 7 8 9 10 ...
## $ gender: Factor w/ 2 levels "female","male": 1 NA 2 1 2 1 2 2 1 2 ...
## $ drug : Factor w/ 2 levels "no","yes": 2 1 1 2 1 1 1 2 2 2 ...
## $ age : num NA 56.5 45.9 64 58 52.9 77.8 56.9 49.9 65.3 ...
## $ weight: int 66 82 65 59 55 75 84 68 66 68 ...
## $ height: int 173 NA 165 160 174 182 169 177 169 175 ...
## $ bmi : num 22.1 NA 23.9 23 18.2 22.6 29.4 21.7 23.1 22.2 ...
## $ bp1 : int 129 122 109 126 NA 106 128 144 118 132 ...
## $ bp2 : int 123 122 105 116 139 109 133 133 117 120 ...
## pid gender drug age weight
## Min. : 1.00 female:53 no :50 Min. :28.90 Min. :53.00
## 1st Qu.: 25.75 male :46 yes :48 1st Qu.:45.40 1st Qu.:63.75
## Median : 50.50 NA's : 1 NA's: 2 Median :51.40 Median :68.50
## Mean : 50.50 Mean :51.23 Mean :69.76
## 3rd Qu.: 75.25 3rd Qu.:56.10 3rd Qu.:76.00
## Max. :100.00 Max. :79.00 Max. :91.00
## NA's :1
## height bmi bp1 bp2
## Min. :154.0 Min. :17.20 Min. : 97.0 Min. : 92.0
## 1st Qu.:164.0 1st Qu.:23.10 1st Qu.:115.5 1st Qu.:111.0
## Median :169.0 Median :24.20 Median :121.0 Median :119.0
## Mean :169.3 Mean :24.23 Mean :121.8 Mean :119.8
## 3rd Qu.:174.5 3rd Qu.:25.10 3rd Qu.:128.0 3rd Qu.:128.0
## Max. :188.0 Max. :32.50 Max. :155.0 Max. :160.0
## NA's :1 NA's :1 NA's :1 NA's :2
Es ist gut, wenn man sensibilisiert ist, dass fehlende Werte
vorhanden sind. Wir müssen für die Analyse aber nichts weiter
unternehmen, weil lm() damit umgehen kann.
Standardmässig gilt: na.action = na.omit. Das bedeutet
jede Zeile, in der entweder die abhängige Variable oder eine unabhängige
Variable fehlende Werte (NA) enthält, wird aus der Analyse
ausgeschlossen.
Berechne die folgenden deskriptiven Statistiken für die Variable
bp1:
Beachte: der Datensatz hat fehlende Werte (NA’s) –>
na.rm = TRUE ist darum nötig.
## [1] 121.8283
## [1] 121
## [1] 119.9804
## [1] 10.95356
## 25% 50% 75%
## 115.5 121.0 128.0
Stelle die Variablen bp1 und bp2 als
Boxplot dar (am besten zwei Boxplots in einer Grafik).
Damit es schöner aussieht, wird hier die x-Achse noch manuell programmiert. Es wird nicht erwartet, dass du das selbstständig tun kannst.
boxplot(df.bp$bp1, df.bp$bp2, xaxt = "none") # xaxt = none --> keine Beschriftung der x-Achse
axis(1, at = c(1,2), labels = c("bp1", "bp2")) # Manuelle Beschriftung der x-Achse (Die beiden Befehle müssen zusammen ausgeführt werden)bp_change (bp2 - bp1) und
füge sie dem Datensatz hinzu. Was ist die mittlere Veränderung von
bp1 zu bp2?Die neue Variable bp_change (bp2 - bp1)
wird wie folgt erstellt. Den Mittelwert können wir mit
mean() berechnen.
## [1] -2.298969
Eine positive Zahl heisst, dass bp2 grösser ist als
bp1., d.h., dass die Veränderung positiv ist (und
umgekehrt). Demnach hat der Blutdruck im Schnitt abgenommen.
bp_change) von 0 unterscheidet (unabhängig von
der Medikamenteneinnahme). Welcher statistische Test ist dafür
geeignet?t.test()bp_change zwischen Personen, welche
ein Medikament eingenommen haben und denjenigen, welche kein Medikament
zu sich nahmen? Stelle die Veränderung pro Gruppe zuerst mittels zwei
Boxplots dar.t.test()In diesem Fall vergleichen wir nicht zwei Gruppen. Somit ist der One Sample t-test (oder paired t-test, was das Selbe ist) angebracht. Beachte, dass \(H_0: \mu_{bp.change} = 0\).
##
## One Sample t-test
##
## data: df.bp$bp_change
## t = -4.1656, df = 96, p-value = 6.789e-05
## alternative hypothesis: true mean is not equal to 0
## 95 percent confidence interval:
## -3.394473 -1.203465
## sample estimates:
## mean of x
## -2.298969
Die mittlere Veränderung von -2.3 mmHg ist bei einem alpha-Level von 5% statistisch signifikant (p-value < 0.001). Unter \(H_0\) ist es also unwahrscheinlich, diese Veränderung oder eine extremere alleine durch Zufall zu finden. Das 95% CI geht von 1.2 bis -3.4 - -1.2. Ob die mittlere Veränderung von 2.3 klinisch relevant ist, sagt uns der t-Test nicht. Bei der Interpretation muss berücksichtigt werden, dass in dieser Stichprobe Personen mit und ohne Medikament nicht separat analysiert wurden. Der Test gibt uns also keine Auskunft über den Effekt des Medikaments.
Im zweiten Teil dieser Aufgabe werden zwei Gruppen (mit und ohne Medikament) verglichen. Daher ist in dieser Situation der two sample t-test angebracht. Es ist eine gute Idee, die Analyse zuerst zu visualisieren, bevor man einen statistischen Test durchführt. In diesem Fall bieten sich Boxplots an:
Unten siehst du den Output des zweistichproben t-Tests. R macht automatisch eine kleine Korrektur (Welch), weil die Varianzen der beiden Populationen als nicht gleich angenommen werden. Beachte, dass \(H_0: \mu_{yes} = \mu_{no}\).
##
## Welch Two Sample t-test
##
## data: df.bp$bp_change by df.bp$drug
## t = 6.131, df = 94.869, p-value = 1.992e-08
## alternative hypothesis: true difference in means between group no and group yes is not equal to 0
## 95 percent confidence interval:
## 3.894398 7.624309
## sample estimates:
## mean in group no mean in group yes
## 0.5510204 -5.2083333
In der Gruppe ohne Medikament hat der Blutdruck um 0.55 zugenommen,
während der Blutdruck in der Gruppe mit Medikament um 5.21 abgenommen
hat. Der geschätzte mittlere Zwischengruppenunterschied der Veränderung
ist demnach -5.76 mmHg (“yes” versus “no” [R rechnet
“no”-“yes”]). Diese Mittelwertsdifferenz ist bei einem alpha-Level von
5% statistisch signifikant (p-value < 0.001). Sollte also \(H_0\) sitmmen, ist ein solches oder ein
noch extremeres Ergebnis sehr unwahrscheinlich. Das angegebene 95% CI
geht von -7.62 bis -3.9. Wir vertrauen zu 95% darauf, dass die wahre
Blutdruckreduktion durch das Medikament, relativ zur Kontrolle, zwischen
diesen Grenzen liegt. Ob ein solcher Effekt klinisch relevant ist, sagt
uns der Test nicht.
Anmerkung: Wir gehen hier davon aus, dass die Daten nicht durch andere Einflüsse verzerrt sind.
Oben hast du mit Hilfe des t-Tests untersucht, ob die Veränderung
bp2 - bp1 davon abhängig ist, ob eine Person ein Medikament
nahm oder nicht. Um diese Frage zu beantworten, kann statt eines t-Tests
auch ein lineares Regressionsmodell gebraucht werden (was mathematisch
äquivalent ist).
bp_change als
abhängige Variable und drug als Prädiktorvariable: \(Y_i = \beta_0 + \beta_1 x_i + \epsilon_i\),
wobei \(Y = bp\_change\) und \(x = drug\). Lass dir eine Zusammenfassung
dieses Modell anzeigen. Tipp: lm(),
summary().Zuerst passen wir das entsprechende Modell an und schauen uns die Zusammenfassung davon an:
##
## Call:
## lm(formula = bp_change ~ drug, data = df.bp)
##
## Residuals:
## Min 1Q Median 3Q Max
## -9.792 -3.551 -0.551 2.449 15.449
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 0.5510 0.6607 0.834 0.406
## drugyes -5.7594 0.9392 -6.132 1.98e-08 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 4.625 on 95 degrees of freedom
## (3 observations deleted due to missingness)
## Multiple R-squared: 0.2836, Adjusted R-squared: 0.276
## F-statistic: 37.6 on 1 and 95 DF, p-value: 1.976e-08
Die Steigung (\(\hat{\beta}_1\)) ist
die Mittelwertsdifferenz, welche oben (beim t-Test) schon berechnet
wurde. Das Intercept ist \(\hat{y}\)
(bp_change), wenn \(x\)
(drug) 0 ist. Wenn man kein Medikament nimmt (die Variable
drug also den Wert 0 annimmt), ist die mittlere
Blutdruckveränderung 0.551 (Aufgabe 4.). Dieser Wert ist identisch mit
dem, den du mit dem t-Test berechnet hast.
Der t-Wert ist der gleiche, wie derjenige beim t-Test. Der t-Wert berechnet sich aus \(\hat{\beta}_1/se = -5.7594/0.9392\). Ein lineares Regressionsmodell mit einer dichotomen Prädiktorvariable liefert also die gleichen Resultate wie ein t-Test (abgesehen von der Welch-Korrektur). Exakte Übereinstimmung wäre ein t-Test mit homogenen Varianzen, auch wenn hier mit den gedruckten Kommastellen kein Unterschied feststellbar ist.
##
## Two Sample t-test
##
## data: df.bp$bp_change by df.bp$drug
## t = 6.132, df = 95, p-value = 1.976e-08
## alternative hypothesis: true difference in means between group no and group yes is not equal to 0
## 95 percent confidence interval:
## 3.894749 7.623959
## sample estimates:
## mean in group no mean in group yes
## 0.5510204 -5.2083333
Anmerkung: Durch die Welch-Korrektur kann es zu kleinen Unterschieden
kommen. R macht automatisch eine Welch-Korrektur, falls die Varianzen in
den beiden Gruppen nicht identisch sind. Mit
var.equal = TRUE als zusätzliches Argument in der
t.test() Funktion wird t.test() und
lm() zum exakt gleichen Ergebnis kommen.
bp1 und
bp2. Tipp: plot()confint()bp2 schätzt das
Modell für eine Person mit bp1 = 140?Wir visualisieren die Analyse zuerst mit einem Scatterplot:
Anhand der Grafik erwarten wir einen starken Zusammenhang zwischen den beiden Variablen. Wir passen nun das Modell an und schauen die Zusammenfassung davon an:
##
## Call:
## lm(formula = bp2 ~ bp1, data = df.bp)
##
## Residuals:
## Min 1Q Median 3Q Max
## -13.0245 -3.3893 -0.0881 3.9283 16.8956
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -10.04294 6.17738 -1.626 0.107
## bp1 1.06352 0.05047 21.072 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 5.419 on 95 degrees of freedom
## (3 observations deleted due to missingness)
## Multiple R-squared: 0.8238, Adjusted R-squared: 0.8219
## F-statistic: 444 on 1 and 95 DF, p-value: < 2.2e-16
Das Intercept beträgt -10.043. Das ist der
durchschnittlich erwarterte Wert von bp2, wenn
bp1 = 0 ist. Die inhaltliche Interpretation des Intercepts,
inkl. dessen SE, t-Wert und p-Wert ist also wenig sinnvoll. Die
Steigung beträgt 1.064. Das heisst wenn
bp1 um 1 steigt, dann steigt bp2
durchschnitlich um 1.064 mmHg. Die Hypothese, dass diese Steigung 0 ist
(\(H_0\)), erweist sich als wenig
plausibel (p < 0.001).
Eine positive Steigung macht in diesem Fall (auf den ersten Blick)
wenig Sinn. Eigentlich würde wir doch eine negative Steigung erwarten,
weil der mittlere Blutdruck abnimmt. Man muss jedoch beachten, dass bei
der Regressionsgleichung auch das Intercept berücksichtigt werden muss.
Wenn man das tut, erhält man für bp2 jeweils einen tieferen
Wert als für bp1. Für bp1 = 140 schätzt das
Modell z.B. einen Wert von \(-10.043 + 1.064 *
140 = 138.917\).
Achtung: Dieses Modell sagt nichts über den Effekt des Medikaments aus!
Konfidenzintervalle für die Koeffizienten erhalten
wir durch die Funktion confint():
## 2.5 % 97.5 %
## (Intercept) -22.3065973 2.220715
## bp1 0.9633251 1.163722
Wir Vertrauen zu 95% darauf, dass sie die wahre Steigung im Intervall [0.963; 1.164] befindet. Das Konfidenzintervall ist konsistent zum sehr kleinen P-Wert.
Die geschätzten Parameter aus dem Output können nun in die
Regressionsgelichung eingesetzt werden. Welchen durchschnittlichen Wert
von bp2 schätzt das Modell für eine Person mit
bp1 = 140?
\[ \hat{y_i} = \hat{\beta_0} + \hat{\beta_1} x_i = -10.043 + 1.064 * 140 = 138.917 \]