Condition abhängige Summation

Allgemeine Statistik mit R, die Test-Methode ist noch nicht bekannt, ich habe noch keinen Plan!

Moderatoren: EDi, jogo

bigben
Beiträge: 2771
Registriert: Mi Okt 12, 2016 9:09 am

Re: Condition abhängige Summation

Beitrag von bigben »

Hi!

Der Code sieht doch ganz sauber aus.

Code: Alles auswählen

data_manyDeathsCause = data_manyDeaths$Cause

# remove duplicated causes
data_manyDeathsCause = data_manyDeathsCause[!duplicated(data_manyDeathsCause)]
Wenn ich das richtig lese, wird es etwas lesbarer mit unique als

Code: Alles auswählen

data_manyDeathsCause <- unique(data_manyDeaths$Cause)
Vielleicht kann man z.B. die Schleife einfach in einer Zeile hinschreiben :P
Von C kommend ist Dir natürlich klar, dass man viele Funktionsaufrufe miteinander verschachteln kann, sodass sie zwar in weniger Zeilen passen, die Lesbarkeit aber sinkt (bei C gerne auch gegen Null). Du hast das so schön lesbar gecoded, dass Du da nicht hin willst.

Code: Alles auswählen

for (cause_val in data_manyDeathsCause)
{
  # get data by cause
  res_tmp = subset(result, result$Cause == cause_val)
Da zeichnet sich natürlich ein Muster ab, dass man in R vielleicht eher mit einer Funktion höherer Ordnung als mit einer for-Schleife angehen würde. Also den Inhalt des Schleifenblocks in eine Funktion packen und dann beispielsweise mit by() (oder tapply für einzelne Spalten) aufrufen. Solange man nicht an Performance-Grenzen stößt, spricht aber überhaupt nichts gegen for-Schleifen.

Als Softwareentwickler mit dieser Art von Problem ist es für Dich vielleicht interessant zu hören, dass man mit einem Zusatzpaket SQL in R einbinden kann, sodass sich solche "Zusammenfassungsprobleme" auch direkt in SQL formulieren lassen, ohne dass man R verlassen muss: https://www.r-bloggers.com/make-r-speak-sql-with-sqldf/

LG,
Bernhard
---
Programmiere stets so, dass die Maxime Deines Programmierstils Grundlage allgemeiner Gesetzgebung sein könnte
jogo
Beiträge: 2085
Registriert: Fr Okt 07, 2016 8:25 am

Re: Condition abhängige Summation

Beitrag von jogo »

Hallo Florian,

der Code sieht recht gut aus, Gratulation!
Für die Zuweisung verwende ich immer <-, damit hat man eine sichtbare Trennung zum Setzen von Parametern (dort ist notwendig param=Wert).
Vielleicht geht noch etwas an dieser Stelle zu optimieren:

Code: Alles auswählen

# extract causes for death
# remove duplicated causes
data_manyDeathsCause <- unique(data_manyDeaths$Cause)  ## vielleicht auch levels()

# drop levels which are 0
data_manyDeathsCause = droplevels(data_manyDeathsCause)
Insgesamt legst Du recht viele Objekte als Zwischenergebnis ab - ich bin da eher sparsam.
Vor 15 Jahren habe ich auch immer reichlich Zwischenergebnisse angelegt ;)

An der for-Schleife ist nicht auszusetzen, besonders, weil Du Grafiken erzeugen möchtest.
Wenn Du die Datenverarbeitung von der Erstellung der Grafiken trennen möchtest, dann sind Listen fällig:

Code: Alles auswählen

L <- split(result, result$Cause)
# und dann weiter mit lapply(L, ...)
# oder for (li in L) { ... }
Es gibt zwar die Funktion by(), aber ich empfinde das Ergebnisobjekt als recht seltsam.

Die Funktionen für das Rechnen mit gruppierten Daten sind in base R nicht einheitlich designed. Deshalb gibt es heute Zusatzpakete, die diese Funktionalität neu verpackt haben - und nicht nur neu verpackt, sondern auch die internen Abläufe mehr oder weniger optimiert haben.

Gruß, Jörg
flowe
Beiträge: 6
Registriert: Di Mai 14, 2019 12:57 pm

Re: Condition abhängige Summation

Beitrag von flowe »

Hallo,
danke für die Antworten. Sorry das es mit meiner Antwort etwas dauerte, aber war einfach mit anderen Dingen ziemlich eingespannt.

@ bigben
Der Code sieht doch ganz sauber aus.
Danke für die Blumen :P
Wenn ich das richtig lese, wird es etwas lesbarer mit unique ..
Das ist ein guter Tip
Da zeichnet sich natürlich ein Muster ab, dass man in R vielleicht eher mit einer Funktion höherer Ordnung als mit einer for-Schleife angehen würde. Also den Inhalt des Schleifenblocks in eine Funktion packen und dann beispielsweise mit by() (oder tapply für einzelne Spalten) aufrufen. Solange man nicht an Performance-Grenzen stößt, spricht aber überhaupt nichts gegen for-Schleifen.
Ich werde mir die Alternative auf jeden Fall mal anschauen. Wie gesagt für einen C/C++ Entwickler sind das viele Befehle die man erstmal überblicken muss. Weil man kann ja auch nicht alles mit allem verwenden (Stichwort Faktoren und Zahlen).
Als Softwareentwickler mit dieser Art von Problem ist es für Dich vielleicht interessant zu hören, dass man mit einem Zusatzpaket SQL in R einbinden kann, sodass sich solche "Zusammenfassungsprobleme" auch direkt in SQL formulieren lassen, ohne dass man R verlassen muss: https://www.r-bloggers.com/make-r-speak-sql-with-sqldf/
Danke für den coolen Tip. Aber ob du es glaubst oder nicht. Ich habe bisher noch nie mit Datenbanken programmiert... Die findet man selten auf MikroControllern :P

Auf jeden Fall Danke für das tolle Feedback!!



@ Jörg
der Code sieht recht gut aus, Gratulation!
Danke für die Blumen :P
Für die Zuweisung verwende ich immer <-, damit hat man eine sichtbare Trennung zum Setzen von Parametern (dort ist notwendig param=Wert).
Muss ich mal überlegen. ich bin halt eher das = gewohnt. Oder in C/C++ das -> :D. Damit ist es ja dann gar nicht mehr so fremd...
Mit dem Vorschlag zu unique.. Danke da bist du dir ja mit bigben einig... dann muss es ja gut sein ;)
An der for-Schleife ist nicht auszusetzen, besonders, weil Du Grafiken erzeugen möchtest.
Wenn Du die Datenverarbeitung von der Erstellung der Grafiken trennen möchtest, dann sind Listen fällig:
Hm ok. Noch ein Punkt den ich mir anschauen muss. (Mir fehlt hier der Affen-Smily der die Hände vor dem Kopf hält)
Ja ich muss noch einiges lernen...
Die Funktionen für das Rechnen mit gruppierten Daten sind in base R nicht einheitlich designed. Deshalb gibt es heute Zusatzpakete, die diese Funktionalität neu verpackt haben - und nicht nur neu verpackt, sondern auch die internen Abläufe mehr oder weniger optimiert haben.
Auf welche Funktionen spielst du da an? Meinst du das aggregate oder dplyr?

Auch dir nochmal vielen Dank

Viele Grüße Florian


PS: hier noch die Daten, welche ich von der WHO downgeloadet habe. Ich lasse die jetzt erstmal auf meiner Seite, da die zu groß sind um hier hochgeladen zu werden. Man könnt diese Daten natürlich auch direkt von der WHO-Datenbank downloaden...

https://www.tastic.cc/Mortality_2015_19 ... Africa.csv

PPS: Um die Daten zu verwenden musste man erst noch ein paar Zeilen am Anfang des Files entfernen damit man diese importieren konnte. (Vielleicht muss man es auch nicht ich habe es jedenfalls nicht ohne hinbekommen.)
Wenn dazu eine Anleitung erwünscht ist kann ich die auch zur Verfügung stellen. Ich denke das die WHO-Daten ja predistiniert ist für Statistik...
Falls ja kann es aber etwas dauern bin wie anfangs erwäht gerade etwas eingespannt...
jogo
Beiträge: 2085
Registriert: Fr Okt 07, 2016 8:25 am

Re: Condition abhängige Summation

Beitrag von jogo »

Hallo Florian,
flowe hat geschrieben: Di Mai 21, 2019 3:09 pm @ Jörg
Für die Zuweisung verwende ich immer <-, damit hat man eine sichtbare Trennung zum Setzen von Parametern (dort ist notwendig param=Wert).
Muss ich mal überlegen. ich bin halt eher das = gewohnt. Oder in C/C++ das -> :D. Damit ist es ja dann gar nicht mehr so fremd...
Vorsicht mit dem Operator -> in R ...
https://stackoverflow.com/questions/517 ... e-an-error
Mit dem Vorschlag zu unique.. Danke da bist du dir ja mit bigben einig... dann muss es ja gut sein ;)
in ähnlichen Situationen kann auch levels() geeignet sein - das hängt auch davon ab, ob man es mit factor oder mit character zu tun hat.
An der for-Schleife ist nicht auszusetzen, besonders, weil Du Grafiken erzeugen möchtest.
Wenn Du die Datenverarbeitung von der Erstellung der Grafiken trennen möchtest, dann sind Listen fällig:
Hm ok. Noch ein Punkt den ich mir anschauen muss. (Mir fehlt hier der Affen-Smily der die Hände vor dem Kopf hält)
Ja ich muss noch einiges lernen...
das mag wohl sein, aber wenn man die Listen gezähmt hat, kann man wahre Wunderwerke mit denen anstellen.
Die Funktionen für das Rechnen mit gruppierten Daten sind in base R nicht einheitlich designed. Deshalb gibt es heute Zusatzpakete, die diese Funktionalität neu verpackt haben - und nicht nur neu verpackt, sondern auch die internen Abläufe mehr oder weniger optimiert haben.
Auf welche Funktionen spielst du da an? Meinst du das aggregate oder dplyr?
aggregate() ist base R. ja, das Paket dplyr gehört zu diesen neueren Paketen. Vom selben Autor gab es vorher noch plyr https://cran.r-project.org/web/packages/plyr/index.html
Mein Liebling ist data.table - hochgradig optimiert https://cran.r-project.org/web/packages ... index.html
PS: hier noch die Daten, welche ich von der WHO downgeloadet habe. Ich lasse die jetzt erstmal auf meiner Seite, da die zu groß sind um hier hochgeladen zu werden. Man könnt diese Daten natürlich auch direkt von der WHO-Datenbank downloaden...
https://www.tastic.cc/Mortality_2015_19 ... Africa.csv
PPS: Um die Daten zu verwenden musste man erst noch ein paar Zeilen am Anfang des Files entfernen damit man diese importieren konnte. (Vielleicht muss man es auch nicht ich habe es jedenfalls nicht ohne hinbekommen.)
evtl. read.table(..., skip=...)
Jedenfall müssen bei den Daten, die Du geliefert hast, keine Zeilen entfernt werden.

Danke für die Daten, dann kann ich etwas rumspielen.

Gruß, Jörg
bigben
Beiträge: 2771
Registriert: Mi Okt 12, 2016 9:09 am

Re: Condition abhängige Summation

Beitrag von bigben »

Hi,
flowe hat geschrieben: Di Mai 21, 2019 3:09 pmIch werde mir die Alternative auf jeden Fall mal anschauen. Wie gesagt für einen C/C++ Entwickler sind das viele Befehle die man erstmal überblicken muss. Weil man kann ja auch nicht alles mit allem verwenden (Stichwort Faktoren und Zahlen).
Ja, leider. C++ wird ja gerne vorgeworfen, dass es zu komplex sei, weil immer wieder neue Dinge obendrauf geschraubt wurden. R hat ein ähnliches Problem: Die Sprache ("S") ist halt richtig alt und die Leute hatten Jahrzehnte, immer irgendwas dazu zu erfinden, was nicht immer gut mit dem davor und danach harmonieren musste. So ist die Standardbibliothek riesig. Nach Jahren des Hobbygebrauchs finde ich immer wieder Funktionen, die ich vorher nie gesehen habe (Hand hoch, wer sinpi() kennt...? Fand wohl mal jemand wichtig, dass man das implementiert und zu base hinzufügt.).

Was die Faktoren angeht: Vielleicht hilft es, sie sich als enum vorzustellen, nur halt dynamisch für den Gebrauch in einer REPL.

LG,
Bernhard
---
Programmiere stets so, dass die Maxime Deines Programmierstils Grundlage allgemeiner Gesetzgebung sein könnte
jogo
Beiträge: 2085
Registriert: Fr Okt 07, 2016 8:25 am

Re: Condition abhängige Summation

Beitrag von jogo »

Hallo Florian,

hier ist die etwas sicherere Variante für die Aggregation:

Code: Alles auswählen

# build sum of died people (independet of sex) per cause
Cols   <- c("Year", "Cause", as.character(c(0:5, seq(10, 95, 5))))
result <- aggregate(. ~ Year + Cause, data=data_cause[Cols], FUN = sum)
übrigens hat aggregate() auch einen Parameter subset= ...

Code: Alles auswählen

# get data with vector of causes (many deaths) from all years
# data_cause = data_country[data_country$Cause %in% data_manyDeathsCause, ]
# build sum of died people (independet of sex) per cause
Cols   <- c("Year", "Cause", as.character(c(0:5, seq(10, 95, 5))))
result <- aggregate(. ~ Year + Cause, FUN = sum, data=data_country[Cols], subset=Cause %in% data_manyDeathsCause)
Momentan frage ich mich, ob der Teil

Code: Alles auswählen

# Set all data are not available to 0
data_manyDeaths[is.na(data_manyDeaths)] = 0
zwingend notwendig ist. Vielleicht kann man ihn weglassen und statt dessen bei aggregate(..., na.action=na.pass, na.rm=TRUE)
Das na.rm=TRUE soll an die Funktion sum() weitergereicht werden.
Wenn man das so mach, dann gibt es in result vier Zeilen mehr, in denen einige Werte NA sind:

Code: Alles auswählen

#Lade CSV Daten der WHO
data = read.csv2("https://www.tastic.cc/Mortality_2015_1999_Germany_SouthAfrica.csv", header = TRUE, sep = ",", check.names = FALSE)

data <- data0
# Hole Daten f?r ein Land
data_country = subset(data, Country == "South Africa")

# remove the total deaths
data_countryYear = subset(data_country, Cause != "TOT")

# Get data where many peaple died at group 30                          
data_manyDeaths = subset(data_countryYear, `30` > 2000)

# Get Data for age 30
#data_manyDeaths = data_manyDeaths[order(data_manyDeaths$`30`), ]

# extract causes for death
# data_manyDeathsCause = data_manyDeaths$Cause
# remove duplicated causes
# data_manyDeathsCause = data_manyDeathsCause[!duplicated(data_manyDeathsCause)]
# drop levels which are 0
data_manyDeathsCause <- levels(droplevels(data_manyDeaths$Cause))

# get data with vector of causes (many deaths) from all years
# data_cause = data_country[data_country$Cause %in% data_manyDeathsCause, ]
# build sum of died people (independet of sex) per cause
Cols   <- c("Year", "Cause", as.character(c(0:5, seq(10, 95, 5))))
result <- aggregate(. ~ Year + Cause, FUN = sum, data=data_country[Cols], 
                    subset=Cause %in% data_manyDeathsCause, na.action=na.pass, na.rm=TRUE)
... und weil ich data.table so mag, gibt es hier eine passende Variante:

Code: Alles auswählen

library("data.table")
Data <- fread("https://www.tastic.cc/Mortality_2015_1999_Germany_SouthAfrica.csv")
Data_country <- Data[Country == "South Africa"]
Data_manyDeathsCause <- Data_country[Cause != "TOT" & `30` > 2000, unique(Cause)]
Result <- Data_country[Cause %in% Data_manyDeathsCause, lapply(.SD, sum, na.rm=TRUE), 
                       by=.(Year, Cause), .SDcols=as.character(c(0:5, seq(10, 95, 5)))]
Statt %in% hätte man einen join machen können.
... oder man verpasst dem Datatable Data_country den key Cause

Code: Alles auswählen

# mit einem join:
Result <- Data_country[data.table(Cause=Data_manyDeathsCause), on="Cause", lapply(.SD, sum, na.rm=TRUE), 
             by=.(Year, Cause), .SDcols=as.character(c(0:5, seq(10, 95, 5)))]

# mit key="Cause" für Data_country
setkey(Data_country, "Cause")
Result <- Data_country[Data_manyDeathsCause, lapply(.SD, sum, na.rm=TRUE), 
                       by=.(Year, Cause), .SDcols=as.character(c(0:5, seq(10, 95, 5)))]
Gruß, Jörg
Antworten