Eine Zuweisung mehrmals ausführen ohne eine Schleife zu benutzen

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

Moderatoren: EDi, jogo

Bill
Beiträge: 35
Registriert: Fr Mär 06, 2020 8:04 pm

Eine Zuweisung mehrmals ausführen ohne eine Schleife zu benutzen

Beitrag von Bill »

Hallo Leute,

ich möchte meine erste Kodierungszeile einmal und die Zweite mehrmals nacheinander ausführen, am Besten ohne eine Schleife verwenden zu müssen.
Wie könnte ich das tun?

Ich möchte also die zweite Zeile z.B. 10 mal ausführen, anstatt 10 mal auf "Run the current line" zu clicken?

Code: Alles auswählen

 test <- 1:2
test <- append(test,test[length(test)]+test[length(test)-1]) 
Liebe Grüße

Bill
jogo
Beiträge: 2085
Registriert: Fr Okt 07, 2016 8:25 am

Re: Eine Zuweisung mehrmals ausführen ohne eine Schleife zu benutzen

Beitrag von jogo »

Hallo Bill,

ich weiß garnicht, was Du gegen die Schleife hast:

Code: Alles auswählen

test <- 1:2
for (i in 1:10) test <- append(test,test[length(test)]+test[length(test)-1]) 
Soll das irgendeine Programmieraufgabe sein für die Fibonacci-Zahlen?

effektiver ist:

Code: Alles auswählen

test <- numeric(12)
test[1:2] <- 1:2
for (i in 3:length(test)) test[i] <- test[i-1] + test[i-2]
weniger effektiver aber viel beeindruckender ist:

Code: Alles auswählen

fib <- function(n) if (n==0 | n==1) 1 else fib(n-1) + fib(n-2)
Vectorize(fib)(1:12)
Gruß, Jörg
p.s.:
statt 10-mal klicken kannst Du die Zeile mit copy-paste verzehnfachen. Dann kannst Du die 10 Zeilen markieren und musst nur einmal klicken.
(SCNR)
Bill
Beiträge: 35
Registriert: Fr Mär 06, 2020 8:04 pm

Re: Eine Zuweisung mehrmals ausführen ohne eine Schleife zu benutzen

Beitrag von Bill »

Hallo Jörg,

ich las und hörte und man sagte mir auch, dass (for)Schleifen in R wohl aus diversen Gründen oft nicht das beste Mittel zur Wahl darstellen. Ich selbst kann das noch nicht ausreichend beurteilen.

Von daher lote ich gerade neben der apply Funktionenfamilie auch andere Sachen aus, mit dem Ziel, hin und wieder Schleifen zu ersetzen/zu vermeiden, wenn es sich anbietet.

Dein Beispiel unten mit der Anwendung if else ist in der Tat spannend und ist das, wonach ich suchte.

Liebe Dank =)

Freundliche Grüße

Bill
jogo
Beiträge: 2085
Registriert: Fr Okt 07, 2016 8:25 am

Re: Eine Zuweisung mehrmals ausführen ohne eine Schleife zu benutzen

Beitrag von jogo »

Hallo Bill,
Bill hat geschrieben: Mi Apr 22, 2020 2:06 pm ich las und hörte und man sagte mir auch, dass (for)Schleifen in R wohl aus diversen Gründen oft nicht das beste Mittel zur Wahl darstellen. Ich selbst kann das noch nicht ausreichend beurteilen.
solltest Du dort etwas überprüfbares lesen oder hören zu dieser Argumentation, kannst Du es gerne weiterleiten.
Meistens entsteht diese Meinung aus folgendem Fakt:
vektorisierte Operationen sind schnell.
Wenn man statt einer vektorisierten Operation eine for-Schleife nimmt, ist man nicht so schnell.
Die for-Schleife an sich ist nicht schneller oder langsamer als in anderen Programmiersprachen.
Von daher lote ich gerade neben der apply Funktionenfamilie auch andere Sachen aus, mit dem Ziel, hin und wieder Schleifen zu ersetzen/zu vermeiden, wenn es sich anbietet.
Wenn es darum geht, auf gar keinen Fall eine for-Schleife einzusetzen, sondern statt dessen irgendeine ~apply-Funktion, dann wird das Ergebnis nicht schneller sein als die for-Schleife.
Man nennt diese Krankheit loop-hiding.

Fazit aus den ersten beiden Punkten:
Vektorisierung soll so weit wie möglich genutzt werde: dies sorgt für kompakten Code und gute Geschwindigkeit. Dies ist besonders wichtig für Codeteile, die häufig durchlaufen werden (die inneren Schleifen). Nebenbei bedeutet jede Vektorisierung, dass eine for-Schleife eingespart werden kann. In äußeren Bereichen ist es aus Performancegründen nicht unbedingt notwendig, for-Schleifen durch ~apply-Aufrufe zu ersetzen.
Dein Beispiel unten mit der Anwendung if else ist in der Tat spannend und ist das, wonach ich suchte.
man nennt es Rekursion (das, was bei meinem Code im else-Zweig steht).

Gruß, Jörg
jogo
Beiträge: 2085
Registriert: Fr Okt 07, 2016 8:25 am

Re: Eine Zuweisung mehrmals ausführen ohne eine Schleife zu benutzen

Beitrag von jogo »

Hallo Bill,

hier noch ein kleiner Vergleich der Geschwindigkeit der drei Lösungen:

Code: Alles auswählen

library("microbenchmark")

f1 <- function() { 
  test <- 1:2
  for (i in 1:10) test <- append(test,test[length(test)]+test[length(test)-1]) 
  test
}

f2 <- function() {
  test <- numeric(12);
  test[1:2] <- 1:2;
  for (i in 3:length(test)) test[i] <- test[i-1] + test[i-2]
  test
}

f3 <- function() {
  fib <- function(n) if (n==0 | n==1) 1 else fib(n-1) + fib(n-2);
  Vectorize(fib)(1:12)
}

microbenchmark(forloop= f1(), prealloc=f2(), rekursiv=f3(), unit="relative")
Es sieht bei mir so aus:

Code: Alles auswählen

> microbenchmark(forloop= f1(), prealloc=f2(), rekursiv=f3(), unit="relative")
Unit: relative
     expr        min         lq      mean     median         uq       max neval cld
  forloop   5.257624   5.274714   4.20908   4.097037   3.833012  3.301086   100  b 
 prealloc   1.000000   1.000000   1.00000   1.000000   1.000000  1.000000   100 a  
 rekursiv 271.639508 238.218984 176.51803 174.908861 151.311897 67.918811   100   c
Die von Dir bevorzugte Lösung mit der Rekursion ist um den Faktor 176 langsamer als meine Variante.

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

Re: Eine Zuweisung mehrmals ausführen ohne eine Schleife zu benutzen

Beitrag von bigben »

Hallo Bill,

meine ersten Programmierschritte habe ich in BASIC gemacht, und da waren for-Schleifen der STandard. Dann habe ich C gelernt, und da waren for-Schleifen der Standard.

R bietet sehr viele Möglichkeiten, Schleifen zu konstruieren, die über for hinaus gehen. Es wäre sehr schade, wenn Du all diese anderen Möglichkeiten nicht kennenlernen und nicht nutzen würdest, deshalb ist Dein Ansinnen richtig und ich kann Dich nur darin bestätigen: Versuche, viele Dinge ohne for zu erledigen, damit Du das auch kannst und Dich später von Fall zu Fall entscheiden kannst.

Gegen die for-Schleife in R gibt es zwei gute Argumente. Einmal die vermeintliche Langsamkeit. Wer häufig Datensätze von zehn, hundert oder auch zehntausend Beobachtungen durchforstet, der hat in der Regel kein Problem mit der "Langsamkeit" von for. Dann wartet man halt mal eine halbe Sekunde länger auf das Ergebnis. Oder auch mal 2 Sekunden. Wenn das zehn Minuten Nachdenken über eine elegantere Lösung einspart ist das ein Netto-Zeitgewinn. Das andere Argument ist die Übersichtlichkeit des Codes.

"Ziehe 100 Mittelwerte aus Standardnormalverteilungsstichproben der Größe 15" kann man so schreiben:

Code: Alles auswählen

a = numeric()
for (i in 1:100)
    a[i] <- mean(rnorm(15))


oder man kann es so schreiben:

Code: Alles auswählen

a <- replicate(100,mean( rnorm(15)))
Letzteres ist nicht nur kürzer sondern auch fast Englisch. Du kannst und sollst diese Eleganz nutzen und es wird auch mal vorkommen, dass Du Geschwindigkeitsprobleme bekommst. Das ist aber kein Grund, for zu vermeiden, wo es sich für eine einfache Lösung anbietet oder wo es Dir Zeit erspart, in der Du dann über den richtigen Algorithmus oder den richtigen Test nachdenken kannst.

Fibonacci-Zahlen sind ein schönes Beispiel, sie schnell ein besser ausgewählter Algorithmus die vermeintlichen Geschwindigkeitsvorteile "schnellerer Sprachen" überholen kann.

LG,
Bernhard
---
Programmiere stets so, dass die Maxime Deines Programmierstils Grundlage allgemeiner Gesetzgebung sein könnte
Bill
Beiträge: 35
Registriert: Fr Mär 06, 2020 8:04 pm

Re: Eine Zuweisung mehrmals ausführen ohne eine Schleife zu benutzen

Beitrag von Bill »

Hallo Jörg,
Hallo Bernhard,

also die Gründe, die wohl oft gegen eine Benutzung von (for) Schleifen in R sprächen, die ich mir gemerkt hatte, waren:
1.) for Schleifen sind (sehr) oft langsamer als die "hoch optimierten Funktionen für iterative Berechnungen" sprich die apply()-Funktionen-Familie
2.) die Lesbarkeit der apply Funktionen soll besser sein, weil man gezwungen wird, prägnanter zu programmieren
2.1.) es gibt mehr (viele) Optionen, wie man (for) Schleifen aufsetzen kann, im Gegensatz zu den apply Funktionen, bei denen man mehr genötigt wird, spezifischer zu programmieren

Ich gebe das wie gesagt nur wieder, ich kann es nicht ausreichend einschätzen. Jedoch deckt sich einiges mit dem, was ihr beide aufgeführt habt.

Die Geschwindigkeitsanalyse ist natürlich interessant.
Eleganz scheint hier im Zielkonflikt mit Geschwindigkeit zu stehen :P
Spannend wäre natürlich auch die Geschwindigkeit einer Berechnung mit einer Funktion aus der apply Familie.

Mir erscheint manchmal auch das Konzept von hoch optimierten Funktionen einleuchtender zu sein als das von Schleifen.
Nichtsdestotrotz nehme ich deinen Rat natürlich gern an Bernhard und werde mich auch in Schleifen weiter einlesen um diese besser verstehen und programmieren zu lernen.

P.S.: Es gibt ja bestimmt auch Fälle, in denen man ein Problem NICHT mit solchen Funktionen, aber eben mit Schleifen lösen kann, oder?!
Wenn ja, gibt es das auch umgekehrt?


Vielen lieben Dank euch beiden für die Hilfen

Liebe Grüße

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

Re: Eine Zuweisung mehrmals ausführen ohne eine Schleife zu benutzen

Beitrag von bigben »

Bill hat geschrieben: Do Apr 23, 2020 11:18 pm P.S.: Es gibt ja bestimmt auch Fälle, in denen man ein Problem NICHT mit solchen Funktionen, aber eben mit Schleifen lösen kann, oder?!
Wenn ja, gibt es das auch umgekehrt?
Im Hintergrund läuft es immer auf Schleifen oder Rekursionen hinaus. Rekursion bekommt Probleme bei großen Zahlen, weshalb am Ende wahrscheinlich jedes dieser Kommandos auf eine for- oder while-Schleife hinausläuft, die mal jemand für Dich in C geschrieben hat. Insofern gibt es wahrscheinlich kein Wiederholungsproblem, das man nicht mit einer oder mehreren while-Schleifen lösen könnte.
for Schleifen sind (sehr) oft langsamer
Mach mal eine Stoppuhr-App auf Deinem Handy auf und stoppe mit der Hand, wie lange es dauert, zehn Millionen Wertzuweisungen in einer for-Schleife zu machen:

Code: Alles auswählen

a <- 0
for(i in 1:10000000)
  a <- a + 1
print(a)
Berichte mal hier das Ergebnis für Deinen Computer. Würdest Du das im Arbeitsleben erträglich finden? Wann und wie planst Du an eine Aufgabe zu kommen, die deutlich mehr als zehn Millionen Zuweisungen macht?
Geschwindigkeit ist meistens ein Nicht-Problem. Im wirklichen Leben macht es nichts aus, ob mein PKW 200 oder 300 PS hat. Im wirklichen Leben hängen die meisten von uns überwiegend im Stadtverkehr hinter 15 Jahre alten Opel Astra mit Fahrern mit Hut auf dem Kopf und bestickter Klorolle auf der Kofferraumabdeckung herum.
die Lesbarkeit der apply Funktionen soll besser sein
Habe ich ja auch so geschrieben, ist aber wahrscheinlich auch einfach Übungssache. Ein eingefleischter C++-Programmierer schaut wahrscheinlich auf eine Schleife und erfasst ähnlich schnell was passiert wie wir eine dieser Schleifenversteckfunktionen verstehen. Nichtsdestoweniger: Viele Abläufe, die bei Statistik und Datenauswertung häufig anfallen haben andere Menschen für uns vorprogrammiert und im vektorwertigen Programmieren und in apply-Funktionen hinterlegt, damit wir das Rat nicht immer neu erfinden und dabei immer neue Flüchtigkeitsfehler machen müssen. Also ist es gut, das zu nutzen. Außerdem ist es toll, sich auf Foren und Blogposts und so weiter im Internet stützen zu können, und dazu muss man die dort übliche Sprache sprechen. Du kommst also nicht drum herum, sowohl for-Schleifen als auch apply-Funktionen und vektorwertige Programmierung zu erlernen.

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: Eine Zuweisung mehrmals ausführen ohne eine Schleife zu benutzen

Beitrag von jogo »

Hallo Bill,
Bill hat geschrieben: Do Apr 23, 2020 11:18 pm also die Gründe, die wohl oft gegen eine Benutzung von (for) Schleifen in R sprächen, die ich mir gemerkt hatte, waren:
1.) for Schleifen sind (sehr) oft langsamer als die "hoch optimierten Funktionen für iterative Berechnungen" sprich die apply()-Funktionen-Familie
die apply-Funktionen machen intern nicht sehr viel etwas anderes als die for-Schleife.
Wenn man jetzt noch genauer hingucken möchte, muss man sich den Interpreter-overhead für die for-Schleife und den function-call-overhead bei den apply-Funktionen angucken.
Wesentlich ist jedoch, was innerhalb der Schleife passiert: wenn dort etwas elementweise erledigt wird, was sich vektorisieren lässt, dann hat man mit vektorisierte Operationen den größten Geschwindigkeitsgewinn.
2.) die Lesbarkeit der apply Funktionen soll besser sein, weil man gezwungen wird, prägnanter zu programmieren
ja, und vor allem muss man etwas mehr über die Struktur des Algorithmus nachdenken - das Nachdenken ist immer gut.
2.1.) es gibt mehr (viele) Optionen, wie man (for) Schleifen aufsetzen kann, im Gegensatz zu den apply Funktionen, bei denen man mehr genötigt wird, spezifischer zu programmieren
ja, for-Schleifen sind freestyle - man kann auch viel Unfug programmieren. Diese Gefahr ist bei den apply-Funktionen weniger gegeben.
Die Geschwindigkeitsanalyse ist natürlich interessant.
Eleganz scheint hier im Zielkonflikt mit Geschwindigkeit zu stehen :P
hier mag das zutreffen, aber die Geschmäcker sind verschieden;
Eleganz (Schönheit) liegt im Auge des Betrachters.
Spannend wäre natürlich auch die Geschwindigkeit einer Berechnung mit einer Funktion aus der apply Familie.
ja, nur leider sind Rekursionen den apply-Funktionen nicht zugänglich. - Dafür sind die Operationen, die in apply-Funktionen ausgeführt werden, parallelisierbar.
(das gilt natürlich nur, wenn man auf Teufelszeug verzichtet)
P.S.: Es gibt ja bestimmt auch Fälle, in denen man ein Problem NICHT mit solchen Funktionen, aber eben mit Schleifen lösen kann, oder?!
Wenn ja, gibt es das auch umgekehrt?
nein, den umgekehrten Fall kann es nicht geben, denn R ist auch ohne die apply-Funktionen Turing-vollständig.
https://de.wikipedia.org/wiki/Turing-Vo ... A4ndigkeit

Gruß, Jörg
Bill
Beiträge: 35
Registriert: Fr Mär 06, 2020 8:04 pm

Re: Eine Zuweisung mehrmals ausführen ohne eine Schleife zu benutzen

Beitrag von Bill »

Hallo Bernhard,
Hallo Jörg,

Also die Ausführung der 10000000 Zuweisungen im Rahmen der for Schleife dauerten bei mir in etwa eine knappe Dreiviertelsekunde, also doch ziemlich gering schätze ich.
Das Argument im Sinne von - bringen Sekundeneinsparungen bei alltäglichen Problemstellungen wirklich viel - behalte ich aufjedenfall im Hinterkopf.

Auch wenn sich eben gerade innerhalb einer Schleife etwas das elementweise abgehandelt wird, vektorisieren ließe, dies dann unter Umständen besser mit vektorisierten Berechnungen zu tun, probiere ich mir zu merken.

Die Wiki Seite über die Turing-Vollständigkeit war auch sehr interessant.

Nur der Neugierde halber, was meinst du mit Teufelszeug im Rahmen der fehlenden Anwendungsmöglichkeiten von Rekursionen innerhalb der apply-Funktionen-Familie ? :P


Liebe Grüße

Bill
Antworten