Seite 1 von 1

code effizienter programmieren

Verfasst: Mo Okt 02, 2017 6:35 pm
von janedoe
Schönen gute Abend,

ich habe mehrere if-Bedingungen und darüber eine for-Schleife laufen. Es funktioniert alles und die Schleifen machen auch das, was sie machen sollen. Leider dauert das ganze lange, da ich die for-Schleife von 1:335000 laufen lassen.

Code: Alles auswählen

str(d)
... 
 $ ns: Factor w/ 4 levels "k", "m",..: 4 4 4 4 4 4 4 4 4 4 ...
 $ nsM: Factor w/ 2 levels "N","Y": 1 1 1 1 1 1 1 1 1 1 ...
...

for (i in 1: length(d$ns)){
if (d$ns[i] == "N" & d$nsM[i] == "N"){d$neu[i] = "N"}
else if (d$ns[i] == "N" & d$nsM[i] == "1"){d$neu[i] = "Y"}
else if (d$ns[i] == "l" & d$nsM[i] == "1") {d$neu[i] = "l"}
else if (d$ns[i] == "m" & d$nsM[i] == "1") {d$neu[i] = "m"}
else if (d$ns[i] == "k" & d$nsM[i] == "1") {d$neu[i] = "k"} }

str(d)
... 
 $ ns: Factor w/ 4 levels "k", "m",..: 4 4 4 4 4 4 4 4 4 4 ...
 $ nsM: Factor w/ 2 levels "N","Y": 1 1 1 1 1 1 1 1 1 1 ...
...
 $ neu: chr  "N" "N" "N" "N" ...
Meine Frage wäre, kann ich den obigen Code vereinfache bzw. effizienter schreiben, damit das Programm schneller läuft. Der Plan hinter meinen Zeilen ist folgender: die Daten in ns zeigen die Mengen an, die Werte in nsM ist der Melder, der anschlägt, sobald ns gemessen wird (besteht aus 0 und 1). Jetzt passiert es öfter, dass der Melder anspringt (nsM = 1), jedoch nichts gemessen wird. Dieses Anspringen des Melders möchte ich gerne bei der Auswertung mitberücksichtigen und deshalb kombiniere ich ns und nsM. bei der variable "neu" handelt es sich um die Kombination der beiden unter den oben angebenden Bedingungen.

danke vielmals
glg. J

Re: code effizienter programmieren

Verfasst: Mo Okt 02, 2017 8:00 pm
von jogo
Hallo J.

bist Du Dir wirklich sicher, dass die Logik stimmt? Schau mal:

Code: Alles auswählen

nsM <- factor(c("N", "Y", "Y", "N", "Y", "N"))
nsM=="1"
Das würde bedeuten, dass bei den vier Teilen nach dem else die Bedingung beim if immer FALSE liefert.

Gruß, Jörg

Re: code effizienter programmieren

Verfasst: Di Okt 03, 2017 11:09 am
von janedoe
Hallo Jörg,

danke für den Hinweis, es muss natürlich heißen

Code: Alles auswählen

for (i in 1: length(d$ns)){
if (d$ns[i] == "N" & d$nsM[i] == "N"){d$neu[i] = "N"}
else if (d$ns[i] == "N" & d$nsM[i] == "Y"){d$neu[i] = "Y"}
else if (d$ns[i] == "l") {d$neu[i] = "l"}
else if (d$ns[i] == "m") {d$neu[i] = "m"}
else if (d$ns[i] == "k" ) {d$neu[i] = "k"} }

Bei den letzten drei kann man die zweite Bedingung auch weglassen, da sie sich von selbst ergibt.
Jetzt bekomme ich folgende Fehlermeldung:

Code: Alles auswählen

Error in if (d$ns[i] == "N" & d$nsM[i] == :
  missing value where TRUE/FALSE needed
Wenn ich die for-Schleife nach der ersten if-Anweisung schließe, dann bekomme ich diese Meldung nicht, und in d$neu ist alles auf "N" gesetzt. Sobald ich mehrere if-Schleifen habe, wird die obige Meldung ausgegeben und der code bricht ab.

Irgendwie versteh ich das nicht ganz, da ja eine Bedingung drinnensteht?

Danke und glg.
J.

Re: code effizienter programmieren

Verfasst: Di Okt 03, 2017 11:50 am
von jogo
Hallo J.,
janedoe hat geschrieben: Di Okt 03, 2017 11:09 am Bei den letzten drei kann man die zweite Bedingung auch weglassen, da sie sich von selbst ergibt.
Jetzt bekomme ich folgende Fehlermeldung:

Code: Alles auswählen

Error in if (d$ns[i] == "N" & d$nsM[i] == :
  missing value where TRUE/FALSE needed
Wenn ich die for-Schleife nach der ersten if-Anweisung schließe, dann bekomme ich diese Meldung nicht, und in d$neu ist alles auf "N" gesetzt. Sobald ich mehrere if-Schleifen habe, wird die obige Meldung ausgegeben und der code bricht ab.

Irgendwie versteh ich das nicht ganz, da ja eine Bedingung drinnensteht?
bei den logischen Operatoren helfen oft zusätzliche Klammern für Klarheit:

Code: Alles auswählen

if ((d$ns[i] == "N") & (d$nsM[i] == "N"))
Wichtig ist natürlich auch, dass keine NAs o.ä. in Deinen Daten sind.
danke für den Hinweis, es muss natürlich heißen:

Code: Alles auswählen

for (i in 1: length(d$ns)){
if (d$ns[i] == "N" & d$nsM[i] == "N"){d$neu[i] = "N"}
else if (d$ns[i] == "N" & d$nsM[i] == "Y"){d$neu[i] = "Y"}
else if (d$ns[i] == "l") {d$neu[i] = "l"}
else if (d$ns[i] == "m") {d$neu[i] = "m"}
else if (d$ns[i] == "k" ) {d$neu[i] = "k"} }
Also lautet die Logik: d$neu ist identisch mit d$ns - außer wenn (d$ns[ i ] == "N") & (d$nsM[ i ] == "Y") (in diesem Fall wird d$neu gesetzt zu "Y"). Du solltest genau nach dieser Logik programmieren:

Code: Alles auswählen

d$neu <- ifelse((d$ns=="N") & (d$nsM=="Y"), "Y", as.character(d$ns))
Wenn Du möchtest, kannst Du das Ergebnis anschließend in einen Faktor umwandeln.
Der Gewinn an Effizienz kommt durch die Vermeidung der Schleife und Nutzung vektorisierter Operationen. Bitte lies den Hilfetext der Funktion ifelse() und lass Dir auch die entsprechenden Beispiele vorführen:

Code: Alles auswählen

example("ifelse")
Gruß, Jörg

Re: code effizienter programmieren

Verfasst: Mi Okt 04, 2017 2:47 pm
von janedoe
Hallo Jörg,

vielen lieben Dank!!
Und wieder einmal habe ich viiiiel zu kompliziert gedacht 😒.

Danke und glg.
J.