-
Notifications
You must be signed in to change notification settings - Fork 0
/
datr_multipledat.Rmd
163 lines (121 loc) · 8.63 KB
/
datr_multipledat.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
---
title: "Arbeiten mit mehreren Datensätzen/Dateien"
output:
html_document:
includes:
after_body: footer.html
---
Oft kommt es vor, dass verschiedene Datensätze aus mehreren Versuchen/Experimenten erhoben werden. In solche einem Fall ist es eventuell nötig
1. die Daten aus den verschiedenen Dateien zusammenzutragen und/oder
2. die verschiedenen Datensätze separat auszuwerten.
# 3 Datensätze - 3 Auswertungen
In diesem Beispiel liegen Daten von drei Feldversuchen vor, die sich prinzipiell recht ähnlich sind, aber an drei verschiedenen Orten ("L1", "L2" und "L3") stattgefunden haben. In den Versuchen wurden 89 verschiedene Sorten/Genotypen ("G1"-"G89") in randomisierten, vollständigen Blockanlagen (RCBD) angebaut und schließlich ihr Ertrag gemessen.
Wir wollen hier nicht versuchen die Daten der 3 Orte gemeinsam auszuwerten, sondern separat. Prinzipiell soll also einfach die Auswertung einer einfaktoriellen RCBD, [wie in diesem Beispiel](1f_rcbd.html) durchgeführt werden, nur eben 3 mal hintereinander jeweils pro Ort.
Natürlich kann dies manuell erledigt werden, indem Beispielsweise ein R-Code pro Datensatz angelegt wird und lediglich an bestimmten Stellen Kleinigkeiten geändert werden, sodass sich der Code auf die richtige Excel-Datei bezieht und am Ende auch die Ergebnisse korrekt abspeichert. Diese Vorgehensweise hat aber folgende Probleme:
1. Es wird natürlich mit steigender Anzahl Datensätze (also mehr als 3) schnell unübersichtlich und aufwendig und
2. es muss bei einer nachträglichen Korrektur des Codes die Korrektur in allen R-Codes umgesetzt werden, was nur so nach Flüchtigkeitsfehlern schreit.
Deshalb bietet es sich manchmal an den R-Code so zu schreiben, dass man nur einen einzigen Code für die Auswertung aller Datensätze benötigt. Voraussetzung hierfür ist natürlich, dass die Datensätze und die Auswertungen sich alle sehr ähnlich sind.
# Zur Umsetzung der Analyse
Sagen wir die 3 Dateien lägen alle im selben Ordner und hießen "Environment1.xlsx", "Environment2.xlsx" und "Environment3.xlsx" und außerdem hieße das entsprechende Tabllenblatt innerhalb aller Excel-Dateien immer "Datenblatt". Natürlich könnte man sie alle einzeln [importieren](datr_importexport.html):
```{r, eval=FALSE}
library(readxl)
dat1 <- read_excel("Environment1.xlsx", sheet="Datenblatt")
dat2 <- read_excel("Environment2.xlsx", sheet="Datenblatt")
dat3 <- read_excel("Environment3.xlsx", sheet="Datenblatt")
```
## Loops
Wie man sieht, ist aber der meiste Code hier redundant, da sich lediglich an zwei Stellen pro Zeile die Zahl von 1 bis 3 ändert. Für solche Fälle können sogenannte *loops/Schleifen* genutzt werden. Sie durchlaufen beispielsweise alle geforderten Ziffern nacheinander:
<div class = "row"> <div class = "col-md-6">
```{r}
for (i in c(1,2,3)){
print(i)
}
```
</div> <div class = "col-md-6">
```{r}
for (year in c(2019, 2020, 2021, 2022)){
print(paste("The year is", year))
}
```
</div> </div>
Wie man sieht wird für jedes Element eines Vektors (oben: *i* oder *year*) ausgeführt, was innerhalb der geschweiften Klammern steht. Es wird schnell klar, dass dies uns auch für den Fall mit Environment1 - Environment3 helfen kann. Wir wollen es uns allerdings noch ein wenig schwerer machen.
## list.files
In Wirklichkeit kann es passieren, dass die Dateien nicht mal mit einheitlichen Namen vorliegen. So auch hier, denn es gibt zwar die Datei "Environment1.xlsx", aber die anderen beiden heißen "environment2.xlsx" und "Location3.xlsx". Anstatt die Dateien nun händisch umzubenennen, wollen wir stattdessen einfach mit den Dateinamen arbeiten, die vorliegen. Eine nützliche Funktion ist dabei `list.files()` - sie listet alle Dateien in einem Ordner auf:
```{r}
DatPfad <- "D:/RKurse/MyDatasets/example_multiplefiles/threedatasets/"
DatNamen <- list.files(DatPfad)
DatNamen # Zeige DatNamen
```
Da wir die 3 Dateinamen nun im Vektor `DatNamen` abgespeichert haben, können wir sie auch einzeln mit einem Loop ansprechen:
```{r}
for (i in DatNamen){
print(paste0(DatPfad, i))
}
```
## Listen in R
Um die 3 Dateien nun auch wirklich zu importieren und als Objekt abzuspeichern, bietet sich der R-Objekttyp *Liste* an. Eine Liste kann alle möglichen R Objekte in sich speichern. Ich selbst merke sie mir als einen Vektor voller R-Objekte. Man muss im vornherein auch nicht festlegen wie lange eine Liste wird - man muss lediglich einmalig die leere Liste erstellen. Im Gegensatz zu Vektoren o.ä. spricht man beispielsweise das erste Objekt einer Liste allerdings nicht mit `Vektor[1]` an, sondern mit einer doppelten eckigen Klammer `Liste[[1]]`:
```{r, message=FALSE, warning=FALSE}
library(data.table)
library(dplyr)
library(readxl)
DatListe <- list() # Erstelle leere Liste
for (i in DatNamen){
DatListe[[i]] <- read_excel(path = paste0(DatPfad, i),
sheet = "Datenblatt") %>% data.table
}
```
Nach dem Loop wurden die 3 Dateien als 3 Objekte im `data.table` Format in `Datliste` gespeichert ([mehr zu data.table und dem %>% Befehl gibt's hier](datr_moreadvanced.html)):
<div class = "row"> <div class = "col-md-6">
```{r}
summary(DatListe) # Zeige Infos zur DatListe
```
Hinweis: `Length=4` meint hier die Anzahl Spalten des Datensatzes
```{r}
DatListe[[1]] # Zeige nur erstes Objekt in DatListe
```
</div> <div class = "col-md-6">
```{r}
DatListe # Zeige gesamte DatListe
```
</div> </div>
Wir haben jetzt also mit wenigen Zeilen Code dafür gesorgt, dass alle 3 Excel-Dateien aus einem Ordner importiert und in einer Liste abgespeichert werden. Übrigens würde derselbe Code auch funktionieren, wenn wir beispielsweise nachträglich noch eine vierte Excel-Datei hinzufügen würden.
# Ergebnisliste
Da alle Versuche als einfaktorielle, randomisierte vollständige Blockanlage angelegt wurden, können wir sie mit dem gleichen Modell auswerten. Bei der Auswertung wollen wir uns hier der Einfachheit halber auf die Varianzanalyse beschränken. Auch die ANOVA Ergebnisse können wir direkt in einer Liste speichern:
```{r}
ErgebnisListe <- list() # Erstelle leere Liste
for (i in DatNamen){
mod <- lm(y ~ gen + rep, data=DatListe[[i]])
ErgebnisListe[[i]] <- anova(mod)
}
ErgebnisListe # Zeige ErgebnisListe
```
Wie man sieht ist der Sorteneffekt in allen 3 ANOVAs signifikant (p<0.05).
## Mehrdimensionale Liste
Was ich jetzt hier beschreibe habe ich tatsächlich noch keinen meiner Kollegen jemals anweden sehen - ich selbst fand es aber in mehreren Situationen sehr praktisch. Eventuell deutet das darauf hin, dass es eine bessere Lösung gibt, von der ich nichts weiß, also gerne bescheid sagen.
Die Motivation dahinter ist, dass ich zu einem Datensatz/Modell oft mehr als nur ein Ergebnis (z.B. ANOVA Ergebnisse) speichern möchte. Ich möchte aber nicht immer auch für jeden Ergebnistyp eine Liste erstellen. Deshalb erstelle ich manchmal Liste, die selbst schon wieder wie Tabellen aussehen. Hier ein Beispiel:
```{r}
# Gewünschte Ergebnisse
ErgebnisNamen <- c("n_obs","n_gen","n_rep","ANOVA")
# Erstelle leere Liste
result_list <- matrix(data=list(),
nrow=length(DatNamen),
ncol=length(ErgebnisNamen),
dimnames=list(DatNamen, ErgebnisNamen))
result_list # Zeige leere Liste
```
Man sieht, dass die Liste von vornherein in ihren Dimensionen definiert sein muss. In diesem Fall würde ich gerne für jeden Datensatz die Anzahl Beobachtungen `n_obs`, Anzahl Sorten `n_gen`, Anzahl Blöcke `n_rep` und die ANOVA Ergebnisse `ANOVA` festhalten. Außerdem habe ich die Zeilen und Spalten mit dem `dimnames=` Befehl entsprechend benannt. Nun können wir die leere Liste befüllen:
```{r}
for (i in DatNamen){
result_list[[i, "n_obs" ]] <- nrow(DatListe[[i]])
result_list[[i, "n_gen" ]] <- n_distinct(DatListe[[i]]$gen)
result_list[[i, "n_rep" ]] <- n_distinct(DatListe[[i]]$rep)
mod <- lm(y ~ gen + rep, data=DatListe[[i]])
result_list[[i, "ANOVA"]] <- anova(mod)
}
result_list
```
Die ersten drei Spalten werden praktischerweise ganz einfach wie eine Tabelle angezeigt, da sie je Datensatz auch nur eine Zahl beinhalten. Die letzten Spalte entählt jeweils die gesamte ANOVA Tabelle und kann somit nicht auf diese Weise dargestellt werden. Dennoch sind die Informationen vorhanden - man muss sie lediglich abfragen:
```{r}
result_list[["Environment1.xlsx", "ANOVA"]] # Zeigt nur ANOVA Ergbnisse des Datensates Environment1.xlsx. Übrigens funktioniert result_list[[1, "ANOVA"]] auch!
```
Man kann übrigens auch output von `ggplot()` in solchen Listen abspeichern. Zusammen mit der [Export-Funktion in verschiedene Tabellenblätter derselben Excel-Datei](datr_importexport.html) lässt sich so der Arbeitsprozess in bestimmten Fällen also deutlich effizienter gestalten.