Jakob Richter

merge() – eine kleine Einleitung

Es kann sein, dass man in die Situation kommt verschiedene Datensätze miteinander kombinieren zu wollen. In einer Tabelle steht vielleicht für verschiedene Lebensmittel die Energiewerte und Vitamingehalte und in einer anderen Tabelle steht wie viel von welchem Lebensmittel eine Person gegessen hat. Will man jetzt schnell berechnen, wie viele kcal jede Person zu sich genommen hat kann man das schnell und elegant durch mergen der Datensätze, gefolgt von aggregate() um die kcal für jeden Patienten zusammenzurechnen.
Das ist natürlich nur ein dämliches Beispiel. Der geneigte R-Nutzer wird schon seine eigenen Anwendungen finden. Oft ist es auch viel einfacher Berechnungen an einem Datensatz durchzuführen als Funktionen zu basteln, die sich Daten aus mehreren Datensätzen zusammensuchen.

Das einfachste Beispiel

wie man es auch in jeder Datenbanken/Informationssysteme-Vorlesung vorgesetzt bekommt:
Wir haben zwei Tabellen, welche sich in einer Spalte ein Merkmal teilen.
Erzeugen wir so ein Beispiel in R:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
kartoffeln <- cbind.data.frame(sorte=c("Adretta","Amflora","Markies"), kgpreis=c(1.44,0.76,1.10))
einkauf <- cbind.data.frame(sorte=c("Adretta","Adretta","Amflora","Markies","Amflora"), kunde=c("Huber","Meyer","Meyer","Schmidt","Huber"),kg=c(10,23,5,8,6))
kartoffeln
#     sorte kgpreis
# 1 Adretta    1.44
# 2 Amflora    0.76
# 3 Markies    1.10
einkauf
#     sorte   kunde kg
# 1 Adretta   Huber 10
# 2 Adretta   Meyer 23
# 3 Amflora   Meyer  5
# 4 Markies Schmidt  8
# 5 Amflora   Huber  6

Jetzt wird schnell klar, was wir haben möchten; Eine Tabelle die für jeden Kunden zeigt, was er bezahlen soll.

18
19
20
21
22
23
24
25
26
einkaufmitpreis <- merge(kartoffeln,einkauf)
einkaufmitpreis$zuzahlen <- einkaufmitpreis$kgpreis * einkaufmitpreis$kg
einkaufmitpreis
#     sorte kgpreis   kunde kg zuzahlen
# 1 Adretta    1.44   Huber 10    14.40
# 2 Adretta    1.44   Meyer 23    33.12
# 3 Amflora    0.76   Meyer  5     3.80
# 4 Amflora    0.76   Huber  6     4.56
# 5 Markies    1.10 Schmidt  8     8.80

Das sieht doch schon ganz knorke aus. Die kritiker werden vielleicht anmerken, dass jetzt ja jeder Kunde nur den zu zahlenden Preis für die Bestellung einer Kartoffelsorte weiß. Dem widmen wir uns später.
Zunächst schauen wir, was passiert, wenn ein Kunde eine Bestellung von gleicher Kartoffelsorte hinzufügt.

30
31
32
33
34
35
36
37
38
39
40
einkauf2 <- rbind(einkauf,cbind.data.frame(sorte="Adretta",kunde="Huber",kg=4))
einkauf2mitpreis <- merge(kartoffeln,einkauf2)
einkauf2mitpreis$zuzahlen <- einkauf2mitpreis$kgpreis * einkauf2mitpreis$kg
einkauf2mitpreis
#     sorte kgpreis   kunde kg zuzahlen
# 1 Adretta    1.44   Huber 10    14.40
# 2 Adretta    1.44   Meyer 23    33.12
# 3 Adretta    1.44   Huber  4     5.76
# 4 Amflora    0.76   Meyer  5     3.80
# 5 Amflora    0.76   Huber  6     4.56
# 6 Markies    1.10 Schmidt  8     8.80

Auch das funktioniert zuverlässig. Die Bestellung ist jetzt allerdings zwei mal in der Tabelle. Das bekommen wir jedoch leicht mit aggregate() heraus.

42
43
44
45
46
47
48
aggregate(einkauf2mitpreis[,c("kg","zuzahlen")],by=einkauf2mitpreis[,c("sorte","kunde")],FUN=sum)
#    sorte   kunde kg zuzahlen
#1 Adretta   Huber 14    20.16
#2 Amflora   Huber  6     4.56
#3 Adretta   Meyer 23    33.12
#4 Amflora   Meyer  5     3.80
#5 Markies Schmidt  8     8.80

Jetzt sind die Bestellungen zusammengefasst. Derjenige, der die Kartoffeln einkauft interessiert sich vielleicht eher für:

50
51
52
53
54
aggregate(kg~sorte,data=einkauf2mitpreis,sum)
#    sorte kg
#1 Adretta 37
#2 Amflora 11
#3 Markies  8

So sollte es auch nicht schwer sein, andere Fragestellungen zu beantworten.

Wenn nicht alles passt

dann macht merge meistens vieles richtig. Fällt z.B. die Bestellung mit der Sorte Markies weg…

55
56
57
58
59
60
61
62
einkauf3 <- einkauf2[-4,]
merge(x=kartoffeln ,y=einkauf3)
#     sorte kgpreis kunde kg
# 1 Adretta    1.44 Huber 10
# 2 Adretta    1.44 Meyer 23
# 3 Adretta    1.44 Huber  4
# 4 Amflora    0.76 Meyer  5
# 5 Amflora    0.76 Huber  6

…dann ist sie auch einfach nicht mehr im Ergebnis.
Was ist jedoch, wenn es die Sorte Adretta nicht mehr gäbe. Nicht auszudenken, wenn dann die Bestellungen einfach wegfallen.

64
65
66
67
68
69
70
71
72
73
wenigerkartoffeln <- kartoffeln[-1,]
merge(x=einkauf2, y=wenigerkartoffeln) #Das ist blöd, denn wir wollen die Bestellung ja nicht vergessen
merge(x=einkauf2, y=wenigerkartoffeln, all.x=T) #Schon besser.
#     sorte   kunde kg kgpreis
# 1 Adretta   Huber 10      NA
# 2 Adretta   Meyer 23      NA
# 3 Adretta   Huber  4      NA
# 4 Amflora   Meyer  5    0.76
# 5 Amflora   Huber  6    0.76
# 6 Markies Schmidt  8    1.10

Gut. Dieses Problem ist geklärt. Doch weiteres Unheil kann auf uns zukommen! Im echten Leben stimmen die Spaltennamen selten überein. Was nun?

77
78
79
80
81
82
83
84
85
86
einkauf4 <- einkauf2
colnames(einkauf4)[1] <- "Kartoffelsorte"
merge(x=einkauf4, y=wenigerkartoffeln, all.x=T, by.x="Kartoffelsorte", by.y="sorte") #perfekt
#     sorte   kunde kg kgpreis
# 1 Adretta   Huber 10      NA
# 2 Adretta   Meyer 23      NA
# 3 Adretta   Huber  4      NA
# 4 Amflora   Meyer  5    0.76
# 5 Amflora   Huber  6    0.76
# 6 Markies Schmidt  8    1.10

Kleine Anmerkung zum Schluß: Natürlich kann man auch all.x=T und all.y=T gleichzeitig nutzen.

Leave a Reply