Kapitel 72 Beschreibende Statistik

Computer und Statistik

Wir werden R oft benutzen, um Daten beschreibend zusammenzufassen. Manchmal möchten wir das für jede Statistik (z.B. Mittelwert, Standardabweichung) separat tun, manchmal möchten wir Befehle benutzen, die automatisch eine Tabelle mit allen gewünschten Statistiken erstellen.

72.1 Pakete für dieses Kapitel

library(dplyr)
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union

72.2 Daten für dieses Kapitel

Wir benutzen in diesem Kapitel Daten aus einem in der Zeitschrift Plos One veröffentlichten Artikel hier klicken.

data<-rio::import("https://ndownloader.figstatic.com/files/37930989")
DT::datatable(data, filter='top', options=list(pageLength=5))

72.3 Statistik über Gruppen

Im ersten Beispiel benutzen wir die Funktion tapply, doch beim ersten Versuch ergibt R NA als Resultat. Dieser Fehler passiert mir immer wieder. Was ist passiert? Es gibt fehlende Werte in der Variable bmi und R sagt: Hey, es gibt fehlende Werte, also ist das Resultat auch ein fehlender Wert. Excel geht da anders vor und rechnet einfach den Mittelwert der restlichen Werte.

tapply(data$bmi, data$sex, mean)
## female   male 
##     NA     NA

Wir müssen also R sagen: Rechne den Mittelwert der nicht-fehlenden Werte. Das tun wir mit dem Argument na.rm=TRUE.

tapply(data$bmi, data$sex, mean, na.rm=TRUE)
##   female     male 
## 27.18487 28.14849

Möchten wir mehr als nur den Mittelwert, können wir das auch haben Dank an https://stackoverflow.com/questions/16546630/easy-way-to-combine-mean-and-sd-in-one-table-using-tapply.

mean.sd <- function(x) c(mean = mean(x, na.rm=TRUE), sd = sd(x, na.rm=TRUE))
simplify2array(tapply(data$bmi, data$sex, mean.sd))
##         female      male
## mean 27.184872 28.148487
## sd    5.644268  4.798799

Wollen wir noch die Anzahl Personen dazurechnen, wird es etwas schwieriger. Wir müssen die Funktion length anpassen, damit sie die fehlenden Werte richtig berücksichtig. Dank an http://www.cookbook-r.com/Graphs/Plotting_means_and_error_bars_(ggplot2)/.

# New version of length which can handle NA's: if na.rm==T, don't count them
    length2 <- function (x, na.rm=FALSE) {
        if (na.rm) sum(!is.na(x))
        else       length(x)
    }

Benutzen wir diese Funktion nicht, wird n nicht stimmen.

mean.sd <- function(x) c(n = length(x), mean = mean(x, na.rm=TRUE), sd = sd(x, na.rm=TRUE))
simplify2array(tapply(data$bmi, data$sex, mean.sd))
##           female        male
## n    1545.000000 1169.000000
## mean   27.184872   28.148487
## sd      5.644268    4.798799
mean.sd <- function(x) c(n = length(x, na.rm=TRUE), mean = mean(x, na.rm=TRUE), sd = sd(x, na.rm=TRUE))
simplify2array(tapply(data$bmi, data$sex, mean.sd))
## Error in length(x, na.rm = TRUE): 2 arguments passed to 'length' which requires 1

Mit der Funktion lenght2 stimmt es, jetzt werden nur die Personen gezählt, die keine fehlenden werte in der Variable BMI haben.

mean.sd <- function(x) c(n = length2(x, na.rm=TRUE), mean = mean(x, na.rm=TRUE), sd = sd(x, na.rm=TRUE))
simplify2array(tapply(data$bmi, data$sex, mean.sd))
##           female        male
## n    1475.000000 1112.000000
## mean   27.184872   28.148487
## sd      5.644268    4.798799

Wir können dies mit summary Funktionen überprüfen.

summary(data$bmi)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
##   14.75   23.73   26.85   27.60   30.55   47.55     127

Wir sehen, dass wir 127 fehlende Werte haben. Das ist genau die Differenz der beiden length und length2 Versionen (siehe oben).

1545-1475
## [1] 70
# = 70
1169-1112
## [1] 57
# =  57
70+57
## [1] 127
# = 127

Wir könnten die Resultate auch in eine Tabelle speichern.

mean.sd <- function(x) c(n = length2(x, na.rm=TRUE), mean = mean(x, na.rm=TRUE), sd = sd(x, na.rm=TRUE))
table<-data.frame(simplify2array(tapply(data$bmi, data$sex, mean.sd)))
rio::export(table, "table.xlsx")

Wir könnten diese auch mit dem tidyverse (dplyr) approach tun.

summary_table<-data %>% 
  group_by(sex) %>% 
  summarise(n_bmi=length2(bmi, na.rm=TRUE),
            mean_bmi=mean(bmi, na.rm=TRUE), 
            sd_bmi=sd(bmi, na.rm=TRUE))

Dieser Weg ist vor allem dann sehr attraktiv, wenn wir mehrere Variablen zusammenfassen möchten.

Im folgenden Beispiel wollen wir alle numerischen Variablen zusammenfassen.

summary_table2<-data %>% 
  group_by(sex) %>% 
  summarise(across(where(is.numeric),.fns=list(mean=mean, sd=sd, n=length2), na.rm=TRUE, 
                   .names="{col}_{fn}"))  

Hier wählen wir ein paar einzelne Variablen aus:

summary_table3<-data %>% 
  group_by(sex) %>% 
  summarise(across(c(start_age, bmi, VASscore, ODIscore),.fns=list(mean=mean, sd=sd, n=length2), na.rm=TRUE, 
                   .names="{col}_{fn}"))