Datenliste transformieren (Deskriptive Tabelle)

Alles zum Thema der beschreibenden Statistik

Moderator: jogo

Antworten
Karo93

Datenliste transformieren (Deskriptive Tabelle)

Beitrag von Karo93 »

Hallo,
Ich versuche mich gerade in R einzuarbeiten und bin leider etwas ins stocken gekommen. Folgende Aufgabe bereitet mir Kopfzerbrechen:

Ich habe folgende Daten in einer .txt gegeben:
- Gruppe (1-4)
- Einwanderer (1: ja, 0: nein)
- Interne Bearbeitungsnr (1-200)
- D-Vitamin im Blut
- Gewicht in kg
- Sonnenexposition (0: meiden die Sonne, 1: der Sonne ausgesetzt)
- D-Vitamin-Einnahme
- Alter

Welche ich erfolgreich in R einlesen konnte (df <- read.table("datenliste.txt", header = TRUE) und mir nun in einer Tabelle wiefolgt angezeigt werden:
Bild

Nun möchte ich zu diesen vielen Daten eine Tabelle in diesem Stil erstellen:
Bild

Hier stehe ich aber komplett auf dem Schlauch :oops:

Vllt kann mir ja hier jmd. weiterhelfen. Wäre nett!

Gruß
jogo
Beiträge: 2085
Registriert: Fr Okt 07, 2016 8:25 am

Re: Datenliste transformieren (Deskriptive Tabelle)

Beitrag von jogo »

Hallo Karo,

willkommen im Forum!
Offensichtlich sollen einige Werte der Tabelle je nach Gruppe aggregiert werden.
Im einfachsten Fall ist das getan mit

Code: Alles auswählen

aggregate(cbind(Gewicht, D.Einnahme, ...) ~ Gruppe, data=df, FUN=mean)
Bitte ändere bei cbind(Gewicht, D.Einnahme, ...) noch die Spaltennamen so, wie sie in deinem Dataframe sind (so wie bei str(df) angezeigt). Für eine weitere Verarbeitung des Ergebnisses:

Code: Alles auswählen

ergebnis <- aggregate(...)
(... die Form der Ergebnistabelle muss noch geändert werden)

Gruß, Jörg
Karo93

Re: Datenliste transformieren (Deskriptive Tabelle)

Beitrag von Karo93 »

Super! Danke!

Ich habe dann einfach die Auslegung mit t(ergebnis) geändert und das Resultat dann selber in eine Tabelle übertragen.

Wenn ich jetzt ein 95% Referenzintervall der VitaminEinnahme für bspw. Gruppe 1 und 3 errechnen möchte, wie bekomme ich das hin?

Meine Idee wäre:
fv=df$D.Einnahme
sd(fv)
sd(fv)/sqrt(100)
mean(fv)+1.96*(sd(fv)/sqrt(100))
mean(fv)-1.96*(sd(fv)/sqrt(100))


So komme ich ja leider nur an die VitaminEinnahme von allen Gruppen und nicht von Gruppe 1 und 3 :roll:
Benutzeravatar
EDi
Beiträge: 1599
Registriert: Sa Okt 08, 2016 3:39 pm

Re: Mittelwert + Konfidenzintervall je Gruppe

Beitrag von EDi »

Ich zeige mal ein Beispiel mit dem data.table package.

Zuerst einmal brauchen wir einpaar Daten, da ja kein reproduzierbares Beispiel geliefert wurde:

Code: Alles auswählen

data(iris)
head(iris)
str(iris)
Der iris Datensatz besteht auch vier numerischen Variablen ["Sepal.Length" "Sepal.Width" "Petal.Length" "Petal.Width"] und einer Kategorischen ["Species"]. Es sind Längenmessungen von Blütenblättern für 3 Irisarten. Ziel ist das den Mittelwert und Konfidenzinterval je Art und für jede Variable zu bestimmen.

Zunächst laden wir data.table und machen aus dem iris-Daten ein data.table:

Code: Alles auswählen

library(data.table)
setDT(iris)
str(iris)
Das Konfidenzinterval errechne ich aus dem Standardfehler (SE). Da es dafür keine Funktion in R gibt, schreibe ich mir selbst eine:

Code: Alles auswählen

# function for standard error
se <- function(x) sd(x) / sqrt(length(x))
Jetzt zeige ich zunächst mal wie man den Mittelwert für eine Variable berechnen kann:

Code: Alles auswählen

iris[ , list(mean.Sepal.Length = mean(Sepal.Length)),
      by = Species]
Das liest sich also: Für jede Gruppe in "Species" berechne mir den Mittelwert von "Sepal.Length" und speichere das in einer Spalte "mean.Sepal.Length".

Das lässt sich auf mehrere Funktionen ausweiten (hier das Konfindenzinterval, sowie min und max):

Code: Alles auswählen

iris[ ,list(mean = mean(Sepal.Length),
            upr = mean(Sepal.Length) + qnorm(0.975) * se(Sepal.Length),
            lwr = mean(Sepal.Length) - qnorm(0.975) * se(Sepal.Length),
            min = min(Sepal.Length),
            max = max(Sepal.Length)
            ), 
      by = Species]
Wir müssen auch nicht unbedingt die se() Funktion von oben verwenden, sonder können da auch direkt in data.table machen:

Code: Alles auswählen

iris[ ,list(mean = mean(Sepal.Length),
            upr = mean(Sepal.Length) + qnorm(0.975) * sd(Sepal.Length) / sqrt(.N),
            lwr = mean(Sepal.Length) - qnorm(0.975) * sd(Sepal.Length) / sqrt(.N)
            ), 
      by = Species]
.N ist hier eine schnelle Abkürzung für length(x).

OK, aber wir haben 4 variablen. wie machen wir das auch einmal?

Man könnte alles für jede Variable einzeln tippen:

Code: Alles auswählen

iris[ , list(mean.Sepal.Length = mean(Sepal.Length),
             mean.Sepal.Width = mean(Sepal.Width),
             mean.Petal.Length = mean(Petal.Length),
             mean.Petal.Width = mean(Petal.Width)),
      by = Species]
Das ist nicht falsch, aber was macht man bei 100 Variablen?

Code: Alles auswählen

iris[ , lapply(.SD, mean), 
      by = Species]
Wendet man für jede Gruppen und Variable an. Das ist aber ein ziemliches Monstrum durch, dass man erst mal durchsteigen muss.
Das lapply(.SD, mean) ist hier die Crux.

Hier eine Erklärung
.SD steht für "Subset of Data" . Das gibt einfach nur den kompletten Datenframe zurück, aber in Stücke geteilt für jede Art / Gruppe:

Code: Alles auswählen

iris[ , print(head(.SD, 2)) , by = Species]
Das mit dem lapply ist ein toller Kniff.
lapply wendet eine Funktion (in dem Fall "mean") auf jeden Eintrag einer Liste an (deshalb lapply, list*apply).
.SD gibt uns einen data.frame und ein data.frame ist eine spezielle Art von Listen und jede Spalte ist eigentlich eine Listeneintrag.
Wenn wir lapply auf einen data.frame anwenden, bekommen wir z.b. den Mittelwert für jede Spalte insgesamt:

Code: Alles auswählen

# umwandelt zurück zu data.frame
iris_df <- data.frame(iris)
lapply(iris_df, mean)
Die Warnung die wir bekommen ist klar, weil wir nur Art drin haben und aus kategorischen variablen können wir kein Mittelwert berechnen [Lösung wäre die letzte Spalte auszuklammern.

Code: Alles auswählen

iris[ , lapply(.SD, mean), 
      by = Species]
heißt also:
Für jede Art ('species') berechnen den Mittelwert für jede Variable.

Mit .SDCols können wir die Spalten einschränken:

Code: Alles auswählen

iris[ , lapply(.SD, mean), 
      by = Species,
      .SDcols = c('Sepal.Width', 'Petal.Width')]
Klinkt kompliziert? Ist es auch! data.table zu lernen braucht Zeit. Wenn man die invertiert hat, rentiert es sich aber über lange Sicht hin. Vorallem wenn man mir großen Datenmengen zu tun hat ist data.table unschlagbar was die Performanz anbelangt.

Aber was ist nun wenn wir Mittelwert und Konfidenzintervall für jede Gruppe und jede Variable haben wollen?
Nun, das ist am kompliziertesten...

Ich schreibe mir mal wieder eine Funktion, die Mittelwert udn Konfindezintervall für einen Vektor / Spalten berechnet:

Code: Alles auswählen

my_summary = function(x) list(mean = mean(x), 
                              upr = mean(x) + qnorm(0.975) * se(x),
                              lwr = mean(x) - qnorm(0.975) * se(x))
Das für eine Variable / Spalte anzuwenden ist einfach und funktioniert wie oben beschrieben:

Code: Alles auswählen

iris[ , my_summary(Sepal.Length), 
      by = Species]
Und mittels .SD geht das auch für alle Spalten:

Code: Alles auswählen

iris[ , lapply(.SD, my_summary), 
      by = Species]
nachteil hierbei ist, dass wir nicht mehr wissen was Mittelwert und Konfidenzinterval ist. Ein einfach Lösung wäre einfach eine Spalten hinzuzufügen:

Code: Alles auswählen

(res <- iris[ , lapply(.SD, my_summary), 
      by = Species][ , type := c('mean', 'upr', 'lwr')])
Ich gebe zu, ist etwas unschön. Die reihenfolge ergibt sich aus der Reihenfolge un my_summary()

Ein weitere Möglichkeit wäre dieses Monstrum (was ich nicht erklären werde):

Code: Alles auswählen

iris[ , as.list(unlist(lapply(.SD, my_summary))), 
      by = Species]
Seht ihr den Unterschied? Finde ich aber auch nicht zufrieden stellend, das die Spaltennamen genutzt werden um Information zu kodieren.
Vielleicht weiß ja jemand eine elegantere Lösung?

So, genug Einführung in das Daten aggregieren mit data.table.
Weitere möglichkeiten wären das dplyr package, plyr, doBy und viele mehr. Vielleicht zeigt ja jemand anderes wie man das da machen kann.
Bitte immer ein reproduzierbares Minimalbeispiel angeben. Meinungen gehören mir und geben nicht die meines Brötchengebers wieder.

Dieser Beitrag ist lizensiert unter einer CC BY 4.0 Lizenz
Bild.
jogo
Beiträge: 2085
Registriert: Fr Okt 07, 2016 8:25 am

Re: Datenliste transformieren (Deskriptive Tabelle)

Beitrag von jogo »

Karo93 hat geschrieben:Wenn ich jetzt ein 95% Referenzintervall der VitaminEinnahme für bspw. Gruppe 1 und 3 errechnen möchte, wie bekomme ich das hin?
Meine Idee wäre: ...
So komme ich ja leider nur an die VitaminEinnahme von allen Gruppen und nicht von Gruppe 1 und 3 :roll:
Hier ein Beispiel mit einem der mit R mitgelieferten Datensätze:

Code: Alles auswählen

t.test(iris[iris$Species=="setosa","Sepal.Length"])
Gruß, Jörg
Antworten