code effizienter programmieren

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

Moderatoren: EDi, jogo

Antworten
janedoe

code effizienter programmieren

Beitrag 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
jogo
Beiträge: 2085
Registriert: Fr Okt 07, 2016 8:25 am

Re: code effizienter programmieren

Beitrag 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
janedoe

Re: code effizienter programmieren

Beitrag 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.
jogo
Beiträge: 2085
Registriert: Fr Okt 07, 2016 8:25 am

Re: code effizienter programmieren

Beitrag 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
janedoe

Re: code effizienter programmieren

Beitrag von janedoe »

Hallo Jörg,

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

Danke und glg.
J.
Antworten