Seite 1 von 2

Summierung nach Levelpaaren

Verfasst: Mo Nov 26, 2018 11:42 pm
von FR1712
Guten Abend,

im Anhang habe ich ein kurzes Script, um mein Problem zu verdeutlichen. Folgende Frage: Wie kann man in einem großen Dataframe Summen nach zwei Merkmalen bilden?

Die Daten sind von der Art her wie folgt:

Code: Alles auswählen

> df
      Orte    Sorte 2016 2017 2018
1   Berlin    Äpfel    7   14    7
2   Berlin Pflaumen    4   14   14
3   Berlin Pflaumen   13   12    4
4   Berlin Pflaumen    2    7    5
5   Berlin   Birnen    4   13   14
6  Hamburg   Birnen   11   11    6
7  Hamburg Pflaumen    9    1    6
8  Hamburg Pflaumen   10   13    6
9  Hamburg   Birnen    5   15    5
10 Hamburg    Äpfel    9   12    7
11 Hamburg Pflaumen   14    5    5
12 München   Birnen    8    2    8
13 München Pflaumen   10    8    1
14 München   Birnen    5   11    3
15 München    Äpfel   13    7    7
Die beiden Merkmale, um die es geht, sind vom Typ factor. Für die einzelnen Levelpaare sind im Allgemeinen mehrerere Einträge vorhanden. Diese will ich nun gern summieren, sodass ich am Ende eine Tabelle habe, in der jedes Levelpaar einmal vorkommt und dazu für jedes Jahr die Summe dieses Levelpaares angegeben ist. Im angegebenen Beispiel würden dann die Zeilen mit gleichem Levelpaar summiert, sodass aus den 15 Zeilen am Ende 9 Zeilen werden. Das ganze soll natürlich idealerweise so erfolgen, dass es dazu eine Funktion gibt, sodass man nicht jedes Levelpaar einzeln eingeben muss. Hat da jemand eine Lösung dazu?

Hier unten ist noch ein Überblick gegeben.

Vielen Dank im Voraus und beste Grüße,
Robert

Code: Alles auswählen

str(df)
'data.frame':	15 obs. of  5 variables:
 $ Orte : Factor w/ 3 levels "Berlin","Hamburg",..: 1 1 1 1 1 2 2 2 2 2 ...
 $ Sorte: Factor w/ 3 levels "Äpfel","Birnen",..: 1 3 3 3 2 2 3 3 2 1 ...
 $ 2016 : int  7 4 13 2 4 11 9 10 5 9 ...
 $ 2017 : int  14 14 12 7 13 11 1 13 15 12 ...
 $ 2018 : int  7 14 4 5 14 6 6 6 5 7 ...

Re: Summierung nach Levelpaaren

Verfasst: Di Nov 27, 2018 8:36 am
von jogo
Hallo Robert,

Code: Alles auswählen

aggregate(. ~ Orte + Sorte, data=df, FUN=sum)
und nochmal komlett:

Code: Alles auswählen

###Beispiel###
set.seed(42)
#vorliegende Daten
df <- data.frame(
  Orte =rep(c("Berlin", "Hamburg", "München"), times = c(5,6,4)),
  Sorte =sample(c("Äpfel","Birnen","Pflaumen"), size = 15, replace = T),
  a =sample(1:15, size = 15, replace = T),
  b =sample(1:15, size = 15, replace = T),
  c =sample(1:15, size = 15, replace = T))
colnames(df) <- c("Orte","Sorte", 2016,2017,2018)
df
aggregate(. ~ Orte + Sorte, data=df, FUN=sum)
Gruß, Jörg

Re: Summierung nach Levelpaaren

Verfasst: Di Nov 27, 2018 11:38 pm
von FR1712
Lieber Jörg,
vielen herzlichen Dank erstmal für deine Antwort. Im Beispiel klappt das auch genau so wie erwünscht. Leider klappt es bei meinen echten Daten nicht auf diese Weise. R führt den Befehl aus und erzeugt ein neuen Dataframe. Aber dort wurde eben nicht das umgesetzt, was ich erhofft hatte.
Ich scheue mich etwas davor, meine echten Daten einfach mal hochzuladen, deshalb versuche ich das erstmal zu beschreiben:
Der erste factor hat 10 level, der zweite 33 level. Der durch aggregate erzeugte Dataframe hat 17 level. Rein theoretisch wäre das zwar möglich, aber ich habe reingeschaut und das ist definitiv falsch.

Hier aber mal zum Überblick

Code: Alles auswählen

str(AD)
'data.frame':	52388 obs. of  44 variables:
 $ Metaregion: Factor w/ 10 levels "Bjørneborg-Kristinestad",..
 $ Kategorie : Factor w/ 33 levels "Alkohol_Getränke",..
 $ X1815     : num  NA NA NA NA NA NA NA NA NA NA ...
 $ X1816     : num  NA NA NA NA NA NA NA NA NA NA ...
Mein code sieht jetzt so aus:

Code: Alles auswählen

attach(AD)
AD2 <- aggregate(.~ Metaregion + Kategorie, data = AD, FUN = sum, na.rm = TRUE)
Woran könnte das liegen? Also auf jeden Fall werde ich nochmal ganz genau die Daten überprüfen, ob da alles stimmt. Aber vielleicht weißt du ja Rat?

Beste Grüße,
Robert

Re: Summierung nach Levelpaaren

Verfasst: Mi Nov 28, 2018 6:49 am
von EDi
Rein theoretisch wäre das zwar möglich, aber ich habe reingeschaut und das ist definitiv falsch.
Woran erkennst du das? Wenn du keine reproduzierbares Beispiel zeigen möchtest, ist es sehr schwer für uns das nachzuvollziehen...

Re: Summierung nach Levelpaaren

Verfasst: Mi Nov 28, 2018 7:51 am
von FR1712
Erkennen kann ich das daran, dass in dem neuen Dataframe viele Levelpaare nicht auftauchen, die eigentlich vorhanden sein müssten. Also es wäre ja logisch, dass das verschwindet, was Null wird, aber es fehlen Sachen, deren Summe nicht null ergibt.

Ich wollte jetzt gerade doch einfach mal meine Daten anhängen, aber die Datei ist zu groß. Im Wesentlichen sind die von der Struktur her schon wie ich das im obigen Beispiel dargestellt habe, einziger Unterschied, der mir auffällt besteht darin, dass da sehr sehr viele NAs drin sind. Aber das dürfte da doch eigentlich keine Probleme bereiten, oder?

Mein Code sieht dann ja im Wesentlichen so aus:

Code: Alles auswählen

Arbeitsdaten <- read.csv("Arbeitsdaten.csv")
attach(Arbeitsdaten)
AD2 <- aggregate(.~ Metaregion + Kategorie, data = Arbeitsdaten, FUN = sum, na.rm = T)

Re: Summierung nach Levelpaaren

Verfasst: Mi Nov 28, 2018 8:41 am
von Athomas
Ich wollte jetzt gerade doch einfach mal meine Daten anhängen, aber die Datei ist zu groß.
Dann sende doch einen Teil, der noch passt!?

Code: Alles auswählen

attach(Arbeitsdaten)
Ohoh - wer hat Dir das böse Wort verraten?
Aber ich möchte dazu unserem attach-Beauftragten jogo nicht vorgreifen ;) !

Re: Summierung nach Levelpaaren

Verfasst: Mi Nov 28, 2018 9:04 am
von jogo
Athomas hat geschrieben: Mi Nov 28, 2018 8:41 am
Ich wollte jetzt gerade doch einfach mal meine Daten anhängen, aber die Datei ist zu groß.
Dann sende doch einen Teil, der noch passt!?

Code: Alles auswählen

attach(Arbeitsdaten)
Ohoh - wer hat Dir das böse Wort verraten?
Aber ich möchte dazu unserem attach-Beauftragten jogo nicht vorgreifen ;) !
Glücklicherweise muss ich mich nicht mehr selbst echauffieren, sondern kann ganz lässig verweisen auf:

Code: Alles auswählen

library("fortunes")
fortune(379)
Wenn Du Dir etwas Gutes tun möchtes, vergiss ganz schnell diese Funktion. Der Aufruf der Funktion ist in Deinem Fall so überflüssig wie ein Kropf:

Code: Alles auswählen

Arbeitsdaten <- read.csv("Arbeitsdaten.csv")
### attach(Arbeitsdaten) ### weg damit!
AD2 <- aggregate(.~ Metaregion + Kategorie, data = Arbeitsdaten, FUN = sum, na.rm = T)
Das, was Du meinst, wofür attach() gut sein könnte, erledigt in Deinem Fall der Parameter data = Arbeitsdaten .
Dass Du den Aufruf trotzdem in Deinem Skript stehen hast, ist nur der letzte Beweis dafür, dass Dir nicht klar ist, mit was für einem Teufelszeug Du es zu tun hast.

Gruß, Jörg

Re: Summierung nach Levelpaaren

Verfasst: Mi Nov 28, 2018 9:08 am
von Athomas
Bei "großen Datenmengen" fällt mir immer data.table ein.
Ich gehe davon aus, dass Du alle Variablen, die keine Gruppeneinteilungen darstellen, summieren willst!?

Code: Alles auswählen

library(data.table)
DT <- data.table(Kategorie1=sample(LETTERS[1:10], 50000, replace=TRUE), 
                 Kategorie2=sample(letters[1:10], 50000, replace=TRUE), 
                 matrix(sample(c(NA,1:10), 50000*50, replace=TRUE, prob=c(0.5, rep(0.05,10))), ncol=50))

Ergebnis <- DT[  , lapply(.SD, sum, na.rm=TRUE), by=.(Kategorie1, Kategorie2)]

Re: Summierung nach Levelpaaren

Verfasst: Mi Nov 28, 2018 9:13 am
von jogo
Hallo Robert,

die Behandlung von NAs und fehlenden levels ist in aggregate() oft nicht so, wie man es sich vorstellt. Es gibt dafür weitere Parameter in der Funktion, die man entsprechend setzen muss. ... oder man nimmt gleich ein anderes Werkzeug, bei dem die Regelungen etwas klarer sind, z.B. data.table
Das sieht dann z.B. so aus:

Code: Alles auswählen

library("data.table")
###Beispiel###
set.seed(42)
#vorliegende Daten
dt <- data.table(
  Orte =rep(c("Berlin", "Hamburg", "München"), times = c(5,6,4)),
  Sorte =sample(c("Äpfel","Birnen","Pflaumen"), size = 15, replace = T),
  '2016' =sample(1:15, size = 15, replace = T),
  '2017' =sample(1:15, size = 15, replace = T),
  '2018' =sample(1:15, size = 15, replace = T))
dt
dt[, as.list(colSums(.SD)), by=.(Orte, Sorte)]
Wenn Du aus irgend einem Grund nicht Deine vorhandenen Daten hier einbringen kannst, kannst Du auf alle Fälle Pseudodaten für uns generieren.

Gruß, Jörg
FR1712 hat geschrieben: Di Nov 27, 2018 11:38 pm Im Beispiel klappt das auch genau so wie erwünscht. Leider klappt es bei meinen echten Daten nicht auf diese Weise. R führt den Befehl aus und erzeugt ein neuen Dataframe. Aber dort wurde eben nicht das umgesetzt, was ich erhofft hatte.
Ich scheue mich etwas davor, meine echten Daten einfach mal hochzuladen, deshalb versuche ich das erstmal zu beschreiben:
Der erste factor hat 10 level, der zweite 33 level. Der durch aggregate erzeugte Dataframe hat 17 level. Rein theoretisch wäre das zwar möglich, aber ich habe reingeschaut und das ist definitiv falsch.

Woran könnte das liegen? Also auf jeden Fall werde ich nochmal ganz genau die Daten überprüfen, ob da alles stimmt. Aber vielleicht weißt du ja Rat?

Re: Summierung nach Levelpaaren

Verfasst: Mi Nov 28, 2018 10:34 am
von FR1712
Athomas hat geschrieben: Mi Nov 28, 2018 8:41 am Ohoh - wer hat Dir das böse Wort verraten?
Das haben wir in der Lehrveranstaltung so gelernt :roll:
jogo hat geschrieben: Mi Nov 28, 2018 9:04 am Wenn Du Dir etwas Gutes tun möchtes, vergiss ganz schnell diese Funktion.
Das werde ich beherzigen.
jogo hat geschrieben: Mi Nov 28, 2018 9:04 am Dass Du den Aufruf trotzdem in Deinem Skript stehen hast, ist nur der letzte Beweis dafür, dass Dir nicht klar ist, mit was für einem Teufelszeug Du es zu tun hast.
Ich bin weit entfernt davon, das zu leugnen :lol:

Im Gegenteil, ich arbeite das erste mal richtig mit R. Das macht mir auch großen Spaß, aber ich stoße auf zahlreiche Fragen. Für die meisten Sachen habe ich bisher zwar Lösungen gefunden, aber bei manchen Problemen versagen dann meine Recherchekünste oder eigenen Code-Versuche. Mir fehlen da sicherlich auch die informatischen Kenntnisse.
Wenn die Qualität meiner Fragen deshalb zu wünschen übrig lässt, bitte ich da um Milde. Wie gesagt stelle ich die nur, nachdem ich auch ne Weile vorher selbst probiert habe. Ich versuche das Problem so präzise wie möglich zu beschreiben und nach Möglichkeit Code oder Daten oder so mit anzuhängen. Das mit den Pseudodaten hatte ich ja oben versucht, das hat ja scheinbar nicht so geklappt. Da muss ich wohl noch viel üben, aber ich habe ja bei Athomas jetzt gesehen, wie es geht.

Auf den ersten Blick scheint mir mit dem data.table Ansatz mein Problem gelöst. Das muss ich mir jetzt mal in Ruhe anschauen. Vielen Dank Euch auf jeden Fall erstmal!

Beste Grüße,
Robert :)