for-Schleife und NA-Werte bei min & max

Wie rufe ich R-Funktionen auf, wie selektiere ich Daten, ich weiß nicht genau ....

Moderatoren: EDi, jogo

Antworten
jessi
Beiträge: 100
Registriert: Mo Jul 10, 2017 9:23 am

for-Schleife und NA-Werte bei min & max

Beitrag von jessi »

Liebes Forum,

ich versuche gerade mir aus den Messwerten von 672 Stationen die Parameter min und max und die Anzahl der Fehlwerte ausgeben zu lassen.

Code: Alles auswählen

str(tagesmittel)
Classes ‘data.table’ and 'data.frame':  81984 obs. of  7 variables:
 $ Codename              : chr  "ANDO" "ANDO" "ANDO" "ANDO" ...
 $ dm                    : int  101 201 301 401 501 601 701 801 901 1001 ...
 $ Tagesmittel   : num  -0.6 -0.8 -0.7 -0.7 -0.3 0.3 -0.2 0.7 1.3 2.9 ...
 $ Tag                   : num  1 2 3 4 5 6 7 8 9 10 ...
 $ Monat                 : num  1 1 1 1 1 1 1 1 1 1 ...
 $ TagMon                : chr  "01-01" "02-01" "03-01" "04-01" ...
 $ fw: num  19.7 19.7 19.7 19.7 19.7 ...
Die Variable "tagesmittel" enthält mitunter den Stationsnamen, den Tagesmittelwert (inkl. NA) und den relativen Anteil der Fehlwerte. Um eine besseren Überblick zu bekommen, dachte ich, ich bastle mir ein Data.frame (später dann auch als csv) mit den Informationen Stationsname, Minimum des Tagesmittelwertes und Maximum und den Anteil an Fehlwerten. Insgesamt sind Tagesmittelwerte an 122 Tagen und bei 672 Stationen. Mein Versuch mit der for-Schleife klappt, allerdings nur bedingt und ich komme nicht drauf, wo der Fehler liegen könnte.

Code: Alles auswählen

output <- (data.frame(character(0), len = numeric(0)))
for (i in 1:length(unique(tagesmittel$Codename)) ) {
		temp <- subset(tagesmittel, Codename == unique(tagesmittel$Codename)[i])
		output <- rbind(output, data.frame(temp$Codename[i], min(temp$Tagesmittel, na.rm=T), max(temp$Tagesmittel,na.rm=T), temp$fw[1])) }
Der Output sieht so aus:

Code: Alles auswählen

> output
    Station.i.                                          min                                     max                          fw
1             ANDO                                    NA                                    NA                          19.67
2             AUSS                                    NA                                    NA                          86.89
3             EHRW                                    NA                                    NA                          74.59
...
15           INNS                                  -0.7                                  81.6                           0.00
...
120           DRES                                  -0.2                                  68.5                           0.00
121           ERFU                                    NA                                    NA                         100.00
122           ERLA                                    NA                                    NA                          33.61
123             <NA>                                    NA                                    NA                          35.25
124             <NA>                                    NA                                    NA                         100.00
125             <NA>                                  -0.2                                  44.5                           0.00
...
669             <NA>                                    NA                                    NA                          90.16
670             <NA>                                    NA                                    NA                          93.44
671             <NA>                                    NA                                    NA                          78.69
672             <NA>                                    NA                                    NA                          88.52
Da bei den meisten Stationen NA-Werte auftreten, habe ich den min- und max-Befehl mit dem Zusatz na.rm = T versehen und außerhalb der Schleife funktioniert das auch, innerhalb der Schleife wird bei den Minimum- und Maximum-Werte NA eingesetzt, wenn fw (= Fehlwert) ungleich Null ist. Und was ich auch nicht verstehe ist, dass die Schleife nicht alle Stationen durchläuft, sondern bei 122 aufhört, wobei die min- und max-Werte sowie der Fehlwert bei allen 672 Stationen zu funktionierten scheint. Lediglich bei er Zuordnung der Stationsnamen scheint etwas nicht zu stimmen.

Ich habe ein stark verkürztes csv.File mit einigen Testdaten angehängt.

Danke für eure Hilfe.

Grüße
Jessi
Dateianhänge
test_file_Rforum.csv
(5.05 KiB) 38-mal heruntergeladen
bigben
Beiträge: 2771
Registriert: Mi Okt 12, 2016 9:09 am

Re: for-Schleife und NA-Werte bei min & max

Beitrag von bigben »

jessi hat geschrieben: Do Apr 25, 2019 11:59 am Lediglich bei er Zuordnung der Stationsnamen scheint etwas nicht zu stimmen.
Hallo jessie,

ich habe Deinen Code jetzt noch nicht laufen lassen. Nur vom Lesen stolpere ich über ein Detail in der Zeile, die mit output <- rbind(... beginnt. Dort heißt es

Code: Alles auswählen

temp$Codename[i], 
und ich kann mir nicht vorstellen, warum man etwas in temp mit i referenzieren sollte. Versuch an der Stelle doch mal das i durch eine 1 zu ersetzen. Vielleicht löst das schon das Problem mit den Stationsnamen.

Code: Alles auswählen

temp$Codename[1], 
LG,
Bernhard


PS: Bitte mach das nicht:
mit dem Zusatz na.rm = T
. Da muss nur irgendwo einmal

Code: Alles auswählen

 T <- 0
gesetzt werden, und schon funktioniert das nicht mehr. Deshalb TRUE immer ausschreiben, nie als T abkürzen.
---
Programmiere stets so, dass die Maxime Deines Programmierstils Grundlage allgemeiner Gesetzgebung sein könnte
bigben
Beiträge: 2771
Registriert: Mi Okt 12, 2016 9:09 am

Re: for-Schleife und NA-Werte bei min & max

Beitrag von bigben »

Kann es sein, dass die Station "ATSVPG" im Beispielfile keinen einzigen Tagesmittelwert verzeichnet hat? Dann kann R auch kein Minimum der Tagesmittel berechnen:

Code: Alles auswählen

tagesmittel <- read.csv2("http://forum.r-statistik.de/download/file.php?id=509")
print(tagesmittel[tagesmittel$Station=="ATSVPG",])
print(tagesmittel[tagesmittel$Station=="BEGENK",])
print(tagesmittel[tagesmittel$Station=="BEGENT",])
print(tagesmittel[tagesmittel$Station=="CHDAVO",])
# usw
LG,
Bernhard
---
Programmiere stets so, dass die Maxime Deines Programmierstils Grundlage allgemeiner Gesetzgebung sein könnte
bigben
Beiträge: 2771
Registriert: Mi Okt 12, 2016 9:09 am

Re: for-Schleife und NA-Werte bei min & max

Beitrag von bigben »

Hi,

nochmal ich. Deine for-Schleifenkonstruktion ist sicher einer von über hundert Wegen, diese Werte zu extrahieren. Persönlich finde ich die folgende Option übersichtlicher (bei 672 Stationen spielt Rechengeschwindigkeit noch keine Rolle):

Code: Alles auswählen

tagesmittel <- read.csv2("http://forum.r-statistik.de/download/file.php?id=509")

zusammenfassung <- data.frame(
    min = tapply(tagesmittel$Tagesmittel,    tagesmittel$Station, function(x) min(x, na.rm=TRUE)),
    mittel = tapply(tagesmittel$Tagesmittel, tagesmittel$Station, function(x) round(mean(x, na.rm=TRUE),2)),             
    max = tapply(tagesmittel$Tagesmittel,    tagesmittel$Station, function(x) max(x, na.rm=TRUE)),
    eintraege = tapply(tagesmittel$Tagesmittel, tagesmittel$Station, length),
    fehlende = tapply(tagesmittel$Tagesmittel, tagesmittel$Station, function(x) sum(is.na(x)))
  )

print(zusammenfassung)
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: for-Schleife und NA-Werte bei min & max

Beitrag von jogo »

Schau mal:

Code: Alles auswählen

tagesmittel <- read.csv2("http://forum.r-statistik.de/download/file.php?id=509")

L <- split(tagesmittel, tagesmittel$Station)

myResult <- function(temp) c(Min=min(temp$Tagesmittel, na.rm=TRUE), Max=max(temp$Tagesmittel,na.rm=TRUE), fw=temp$fw[1])
sapply(L, myResult)
Wie ich aber gesehen habe, verwendest Du data.table - damit lässt sich das noch viel eleganter bewerkstelligen:

Code: Alles auswählen

library("data.table")

tagesmittel <- fread("http://forum.r-statistik.de/download/file.php?id=509", dec=",")
tagesmittel[, .(Min=min(Tagesmittel, na.rm=TRUE), Max=max(Tagesmittel, na.rm=TRUE), fw=fw[1]), Station]
so schaut es aus:

Code: Alles auswählen

> tagesmittel[, .(Min=min(Tagesmittel, na.rm=TRUE), Max=max(Tagesmittel, na.rm=TRUE), fw=fw[1]), Station]
    Station  Min  Max     fw
 1:  ADANDO -0.8  0.3  19.67
 2:  ATGLEI -0.8 11.5  79.51
 3:  ATSVPG  Inf -Inf  50.00
 4:  BEGENK  Inf -Inf  31.15
 5:  BEGENT  Inf -Inf 100.00
 6:  CHDAVO  Inf -Inf  64.75
 7:  CHGENE  3.9 13.8  23.77
 8:  CZUORL  1.7 15.8  70.49
 9:  DEDREB -0.9 -0.9  26.23
10:  EEPAER  Inf -Inf  74.59
11:  ESGIJO -0.4  0.5   0.00
12:  ESSAND -0.5 -0.2   1.64
13:  FIKEVO  Inf -Inf 100.00
14:  FRAJAC -0.1  1.2  29.51
15:  GRKAVA  Inf -Inf 100.00
16:  HUMOSD  Inf -Inf  47.54
17:  HUNYIR  Inf -Inf  42.62
18:  UAZAPO  Inf -Inf  88.52
Warnmeldungen:
1: In gmin(Tagesmittel, na.rm = TRUE) :
  No non-missing values found in at least one group. Returning 'Inf' for such groups to be consistent with base
2: In gmax(Tagesmittel, na.rm = TRUE) :
  No non-missing values found in at least one group. Returning '-Inf' for such groups to be consistent with base
Gruß, Jörg
jessi
Beiträge: 100
Registriert: Mo Jul 10, 2017 9:23 am

Re: for-Schleife und NA-Werte bei min & max

Beitrag von jessi »

Lieber Jörg, lieber Bernhard,

vielen Dank für eure Hilfe.
Versuch an der Stelle doch mal das i durch eine 1 zu ersetzen.
Danke, dass hat das Stationsproblem gelöst.
Deshalb TRUE immer ausschreiben, nie als T abkürzen.
Und dieser Tipp hat das NA Problem gelöst. Das Abkürzen mit F und T habe ich jetzt schon so oft gelesen und vermutlich auch angewendet. Diesen Tipp hat mir noch nie jemand gegeben. Danke :)
Kann es sein, dass die Station "ATSVPG" im Beispielfile keinen einzigen Tagesmittelwert verzeichnet hat? Dann kann R auch kein Minimum der Tagesmittel berechnen:
Ja, Bernhard. Leider gibt es nicht an allen Stationen Werte. Bei den Min- und Max-Werte ist es mir eher darum gegangen, dass bei Stationen mit hoher NA-Anzahl der Befehl nicht funktioniert hat.

Danke, Leute, ihr habt mir sehr weitergeholfen. Und bei jedem Eintrag lerne ich etwas dazu :)

Grüße
Jessi
bigben
Beiträge: 2771
Registriert: Mi Okt 12, 2016 9:09 am

Re: for-Schleife und NA-Werte bei min & max

Beitrag von bigben »

jessi hat geschrieben: Do Apr 25, 2019 3:43 pmDanke, Leute, ihr habt mir sehr weitergeholfen. Und bei jedem Eintrag lerne ich etwas dazu :)
Hallo Jessi,

das freut mich sehr. Ich lerne beim Antworten immer noch dazu, z. B. dass min(NA, na.rm=TRUE) als Rückgabewert Inf liefert, wusste ich nicht. Ist keine schlechte Antwort, wenn man drüber nachdenkt.

Wenn ich noch einen Kommentar zu Deiner Schleife los werden darf: Überleg mal, ob da wirklich bei jedem Schleifendurchlauf unique(tagesmittel$Codename) berechnet werden muss, oder ob es nicht möglich wäre, das vor der Schleife nur ein einziges Mal zu berechnen und das Ergebnis in einer Variable abzuspeichern. Wenn Du irgendwann mal vor einer Schleife sitzt, die viele tausend Mal durchlaufen wird, dann kann so etwas den Unterschied zwischen erträglich langsam und unerträglich langsam ausmachen. Der Königsweg in Sachen Geschwindigkeit ist aber ohnehin ganz bestimmt Jörgs Lösung mit data.table.

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: for-Schleife und NA-Werte bei min & max

Beitrag von jogo »

ok, also jetzt zu der Frage, wie würde ich das mit einer klassischen Schleife machen?
Meine Denkmuster sind so, dass ich trotzdem meine Funktion verwenden wollte, die auf dem Subset arbeitet:

Code: Alles auswählen

tagesmittel <- read.csv2("http://forum.r-statistik.de/download/file.php?id=509")

myResult <- function(temp) c(Min=min(temp$Tagesmittel, na.rm=TRUE), Max=max(temp$Tagesmittel,na.rm=TRUE), fw=temp$fw[1])

uStation <- unique(tagesmittel$Station)
output   <- matrix(NA, length(uStation), 3)
rownames(output) <- uStation
for (s in uStation) {
  output[s, ] <- myResult(subset(tagesmittel, Station == s))
}
Da die for-Schleife nur noch einen Ausdruck enthält, geht natürlich auch:

Code: Alles auswählen

for (s in uStation) output[s, ] <- myResult(subset(tagesmittel, Station == s))
Aber wenn man bis hier gekommen ist, dann drängt sich sapply() auf:

Code: Alles auswählen

uStation <- levels(tagesmittel$Station)
sapply(uStation, function(s) myResult(subset(tagesmittel, Station == s)))
Aus Sicht der Beurteilung der Performance würde man sagen können: das ist loop-hiding.
Nun ist aber Performance nicht das einzige Kriterium, nach dem man Code beurteilen sollte.

Gruß, Jörg
Antworten