Didaktik in R

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

Moderatoren: EDi, jogo

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

Didaktik in R

Beitrag von jogo »

Hallo miteinander,

welche Erfahrungen habt Ihr bei der Didaktik in R?
Welcher Rolle spielen noch Konzepte der 3G-Sprachen?
Wie kann man diese vermeiden? ... sondern den Blick öffnen für die Metafunktionen?

Gruß, Jörg
Benutzeravatar
EDi
Beiträge: 1599
Registriert: Sa Okt 08, 2016 3:39 pm

Re: Didaktik in R

Beitrag von EDi »

R kann alles, starke Objektorientierung (S3, R6) und starke funktionelle Elemente (apply familie, purrr) .

Didaktisch würde ich purrr für die funktionelle programmierung lehren, ist viel konsistenter als sapply, lapply, tapply, rapply, vapply, mapply,...

Funktionell in R programmieren ist sehr sehr machtvoll und erleichtert die meiste Zeit das Leben. Der nächste Schritt ist dann das meta-programming (Code aus code erzeugen und ausführen) - wenn man das auch beherrscht hat man R-Superkräfte erlangt und kann fast jedes Problem mit R lösen.
Bitte immer ein reproduzierbares Minimalbeispiel angeben. Meinungen gehören mir und geben nicht die meines Brötchengebers wieder.

Dieser Beitrag ist lizensiert unter einer CC BY 4.0 Lizenz
Bild.
jogo
Beiträge: 2085
Registriert: Fr Okt 07, 2016 8:25 am

Re: Didaktik in R

Beitrag von jogo »

Hallo Edi,

danke für die Antwort. Ich grübele immer noch darüber, wie man am besten vorgeht bei absoluten Programmieranfängern.

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

Re: Didaktik in R

Beitrag von bigben »

Hallo Jörg,

ich denke, dass jede Schleife, die man als Anfänger im ersten Jahr schreibt, gleichermaßen gut mit beidem funktioniert.

Code: Alles auswählen

for(i in 1:10)
oder

Code: Alles auswählen

sapply(1:10, ...)
ist gleichermaßen einfach oder kompliziert. Je mehr ich darüber nachdenke, umso relevanter ist der Unterschied, dass for einen Block wiederholt und *apply eine Funktion wiederholt. Was ein Block ist, erfasst jeder ohne mathematischen Hintergrund schnell. Um sich mit *apply anzufreunden braucht man eine solide Vorstellung davon, was eine Funktion ist. Idealerweise sollte man ein Verständnis von anonymen Funktionen haben oder schnell entwickeln. Wer weder Mathematik- noch Programmierhintergrund hat muss hier anders und aufwändiger dran geführt werden als andere.

Wenn ich einen R-Kurs zu veranstalten hätte, weiß ich nicht, wie ich es machen würde. In der natürlichen Entwicklung eines "R mal ausprobierens" werden Schleifen nützlich, lange bevor man Funktionen braucht: Da hat einer zwanzig Spalten, die er auf Geschlechtsunterschiede untersuchen will und dann zeige ich

Code: Alles auswählen

for(i in 2:21){
    plot(patienten[,i] ~ patienten$sex)
    print(t.test(patienten[,i] ~ patienten$sex))
}
und jeder sieht sofort ein, dass er sich dafür in der SPSS-GUI einen Wolf geklickt hätte. Wer sowas sieht, ist schnell interessiert. Und der Block hat halt Klammern, damit man sieht wo er anfängt und wo er aufhört. Der braucht keinen Namen, keine Argumente, keine return-Werte und dass er side-effects hat ist völlig natürlich.

Ich persönlich neige dazu, bei for prozedural zu denken und bei *apply deklarativ zu denken. Das ist zwar nicht notwendig, aber ich glaube, es bietet sich schon an. Ich mutmaße, dass es für absolute Anfänger leichter ist, prozedural zu denken (sag dem Computer, was er machen soll), aber auch das ist vielleicht von der mathematischen Vorbildung abhängig?

Zuletzt finde ich es gut, dass es for-Schleifen in der einen oder anderen Art auch in fast jeder anderen Programmiersprache (Haskell mal ausgelassen) gibt. Wenn man also in R einführen will, dann braucht man sie lange nicht, wenn man aber in "die Programmierung" einführen will, dann ist die for-Schleife ein guter Freund, auf den man sich bei jeder neuen Sprache freuen kann.

JMTC,
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: Didaktik in R

Beitrag von jogo »

Hallo Bernhard,

danke für Deine Antwort.
Einerseits ist es eine große Chance, dass Neuling noch nicht durch andere Programmiersprachen verdorben sind, andererseits ist es auch eine große Hürde, sofort mit dem ungeheuer flexiblen und kraftvollen Möglichkeiten von R konfrontiert zu sein.
Ist nicht die for-Schleife in R so etwa (nicht ganz so drastisch) wie das goto in den Programmiersprachen der 3. Generation - noch vorhanden, aber weitestgehend unerwünscht?
(Das nicht "ganz so drastisch" deswegen, weil es wirklich Situationen gibt, in denen man mit der for-Schleife klar besser ist. Die for-Schleife halte ich durchaus für notwendig.)
Wenn die for-Schleifen weniger Gewicht bekommen sollen, dann muss man frühzeitig das Erstellen von Funktionen besprechen.

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

Re: Didaktik in R

Beitrag von bigben »

Hallo Jörg,
jogo hat geschrieben: Mo Mai 27, 2019 9:26 amIst nicht die for-Schleife in R so etwa (nicht ganz so drastisch) wie das goto in den Programmiersprachen der 3. Generation - noch vorhanden, aber weitestgehend unerwünscht?
Ich bin mir da nicht so sicher. Es soll ja Sprachen geben, Python etwa oder elm, wo ein noch lebender geistiger Vater der Sprache sagt, was gut und was schlecht ist. Das Zen of Python stammt zwar nicht von Guido von Rossum, gibt aber dennoch wertvolle Grundsätze, die in der Python Community weitgehend akzeptiert werden ("There should be one—and preferably only one—obvious way to do it." oder auch "In the face of ambiguity, refuse the temptation to guess.") Das R Core Team hält sich mit Grundsatzfestlegungen ja doch eher zurück und bloß weil Hadley Wickham in diese Lücks springt, muss man ihm ja nicht die Definitionsgewalt geben. Kann man also sagen, dass dieses oder jenes in R unerwünscht ist, oder macht sich das jeder so, wie es ihm passt?
GOTO stammt aus einer Zeit, als man noch nicht genug Ordnungskonstrukte hatte, um die Dinge sauberer zu erledigen. Wenn ich Code per GOTO aufrufe, kann ich diesem Code Daten nur in globalen Variablen mitteilen und die sind aus gutem Grund böse. for-Schleifen gibt es aber in vielen Sprachen die sehr auf Ordnung im Code achten. (Und manche Leute finden GOTO auch noch in Sprachen aus dem aktuellen Jahrhundert gut: https://stackoverflow.com/questions/110 ... -statement )

Was die "3. Generation" angeht - ich kannte diese Notation nicht, habe Sie gegoolet und hatte den Eindruck, an verschiedenen Stellen verschiedene Definitionen gefunden, die ich für nicht übereinstimmend hielt. Hast Du mal einen Link zu "Deiner" Definition?

Was in meinen Treffern regelmäßig als 5G aufgelistet wurde ist Prolog. Also habe ich mal gegooglet und siehe da: Es gibt schlaue Leute, die eine Schleife für Prolog fordern. Die Argumentation ist zufällig gar nicht soweit weg von meiner oben:

http://citeseerx.ist.psu.edu/viewdoc/su ... 1.1.6.9498
Our initial idea for improving the situation was to provide a comprehensive library of higher-order primitives. A limited versoin of such a library had been available before, providing efficient versions of higher-order predicates like map/3, foldl/4, filter/3 etc. [...] During the redesign, we soon realised that going beyond these basics would require to consider additional concepts like lambda expressions, composition of higher-order predicats [...] This however, would have conflicted with our initial objective: it was unlikely that anything based on such complex concepts would be readily accepted by novices...

Das soll nicht heißen, dass ich den Charme des higher-order nicht nachvollziehen könnte. Ich bin mir nur nicht so sicher, dass Schleifen in R generell abgelehnt würden oder auch abgelehnt werden sollten. Und wenn man sich anschaut, wie elegant eine for-Schleife mit dem foreach-Paket parallelisiert werden kann, ist sie auch nicht unbedingt ein Konzept der Vergangenheit.

Einerseits ist es eine große Chance, dass Neuling noch nicht durch andere Programmiersprachen verdorben sind
Du hast sicher Recht, dass das Bild einer Sprache von den ersten Schritten geprägt wird und wenn man sich mal mit Schleifen zu helfen weiß, dann ist es eine Hürde, sich andere Konzepte anzuschauen, die man "nicht wirklich braucht".

Wenn die for-Schleifen weniger Gewicht bekommen sollen, dann muss man frühzeitig das Erstellen von Funktionen besprechen.
Das ist eben kontextspezifisch. Wenn Du eine Anzahl X Studenten hast, die sich für einen Kurs verpflichtet haben und den in jedem Fall beenden wollen oder wenn ein User Dein Buch gekauft und dafür Geld ausgegeben hat, dann kannst Du mit abstrakten Konzepten anfangen und darauf bauen, dass deren Nutzen sich später schon noch zeigen wird. Wenn Du mehr so eine lockere Option "wenn Du in der Pause mal Zeit hast" als Unterricht anbietest, oder Dein Schüler nicht Dein Buch sondern Deinen Blog liest, dann kann es wichtiger sein, schnell konkrete Ergebnisse zu produzieren. Hast Du denn einen spezifischen Kontext, für den Du die Frage stellst oder ist das mehr so allgemein philosophisch?


Ich habe eine 8jährige Tochter und habe mir lange die Frage gestellt, welche Programmiersprache ich ihr wohl als erstes zeigen werde. (Zu früh? Ich habe gelesen, die Forschung zeige, dass man Mädchen ganz früh für Computer gewinnen müsse, bevor noch die Assoziation entsteht, Computer seien was für Jungen.) Das klingt jetzt vielleicht nach einer ganz anderen Frage, aber so anders ist die gar nicht. Ein
Sprachenkandidat in meinem Kopf war in der Tat Haskell: Minimalistische Syntax, kein Klammernzählen, kein Semicolon am Zeilenende. Stattdessen klare Konstrukte, Funktionen wie aus der Mathematik, gut REPL-fähig. Eine for-Schleife hätte es da gar nicht gegeben, sodass die Frage sich auch nicht gestellt hätte. Eine Sprache mit mathematischer Schönheit, geeignet um Konzepte anstelle von Syntax zu lernen.
Allein -- da hätte ich Jahre warten müssen, bis die Mathematiklehrer die Konstrukte erklären, die in Haskell so schön wiederzufinden sind.
Stattdessen lernt sie jetzt erstmal Scratch: Da ist nix mit Funktionen, dafür Objekte. Die Objekte sind bunte Bilder und alles ist event-driven. Dafür sind die Kommandos in Deutsch verfübar und man hat ratz-fatz lustige Farbeffekte, bewegte Sprites, Soundeffekte und ein Syntax-Error ist, wenn die Puzzleteile nicht zusammen passen. Motivation durch schnelle Erfolge eben. Was aber ein Datentyp ist, ein Rückgabewert, eine Rekursion oder wiederverwendbarer Code, das wird sie damit sicher nicht lernen. Welche Sprache dafür später herhalten muss und ob sie später überhaupt eine "richtige" Sprache lernen will, weiß ich jetzt noch nicht. Die bunten Kätzchen etc. werden ihr bei der "richtigen" Sprache dann aber fehlen.
danke für Deine Antwort
Danke für die Frage. Ich finde es schön, wenn hier im Forum nicht nur nach Code gefragt wird sondern beispielsweise auch, wie man R am besten vermittelt. Gerne auch die Frage, ob wir hier im Forum Schleifen für veraltet halten.

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: Didaktik in R

Beitrag von jogo »

Hallo Bernhard,
bigben hat geschrieben: Mo Mai 27, 2019 3:09 pm
jogo hat geschrieben: Mo Mai 27, 2019 9:26 amIst nicht die for-Schleife in R so etwa (nicht ganz so drastisch) wie das goto in den Programmiersprachen der 3. Generation - noch vorhanden, aber weitestgehend unerwünscht?
Ich bin mir da nicht so sicher. Es soll ja Sprachen geben, Python etwa oder elm, wo ein noch lebender geistiger Vater der Sprache sagt, was gut und was schlecht ist. Das Zen of Python stammt zwar nicht von Guido von Rossum, gibt aber dennoch wertvolle Grundsätze, die in der Python Community weitgehend akzeptiert werden ("There should be one—and preferably only one—obvious way to do it." oder auch "In the face of ambiguity, refuse the temptation to guess.") Das R Core Team hält sich mit Grundsatzfestlegungen ja doch eher zurück und bloß weil Hadley Wickham in diese Lücks springt, muss man ihm ja nicht die Definitionsgewalt geben. Kann man also sagen, dass dieses oder jenes in R unerwünscht ist, oder macht sich das jeder so, wie es ihm passt?
GOTO stammt aus einer Zeit, als man noch nicht genug Ordnungskonstrukte hatte, um die Dinge sauberer zu erledigen. Wenn ich Code per GOTO aufrufe, kann ich diesem Code Daten nur in globalen Variablen mitteilen und die sind aus gutem Grund böse. for-Schleifen gibt es aber in vielen Sprachen die sehr auf Ordnung im Code achten. (Und manche Leute finden GOTO auch noch in Sprachen aus dem aktuellen Jahrhundert gut: https://stackoverflow.com/questions/110 ... -statement )
das "unerwünscht" bezog sich auf GOTO. Dass es dies in R nicht mehr gibt, finde ich in Ordnung - dies bewahrt vor vielen Problemen. Auf GOTO kann besonders gut verzichtet werden, wenn es wie in R die Konstrukte break und next gibt.
Ansonsten bin ich ein Freund davon, dass es durchaus mehrere Möglichkeiten gibt, eine Aufgabe zu strukturieren oder auch zu implementieren.
Und ganz klar: die for-Schleife ist ein Konstrukt, dass in einigen Situationen nur schwer zu ersetzen ist.
Was die "3. Generation" angeht - ich kannte diese Notation nicht, habe Sie gegoolet und hatte den Eindruck, an verschiedenen Stellen verschiedene Definitionen gefunden, die ich für nicht übereinstimmend hielt. Hast Du mal einen Link zu "Deiner" Definition?
Einen Link habe ich nicht, aber ich kann es kurz schreiben:
Das sind für mich die Programmieren, die weitestgehend einzelne Zahlen und Zeichenketten verarbeiten und bei Arrays nur einzelne Felder indizieren, z.B. FORTRAN, Algol, PL1, BASIC, C, Pascal. Irgendwo habe ich für diese auch schon mal den Begriff Universalsprachen gelesen.
Was in meinen Treffern regelmäßig als 5G aufgelistet wurde ist Prolog. Also habe ich mal gegooglet und siehe da: Es gibt schlaue Leute, die eine Schleife für Prolog fordern. Die Argumentation ist zufällig gar nicht soweit weg von meiner oben:

http://citeseerx.ist.psu.edu/viewdoc/su ... 1.1.6.9498
Our initial idea for improving the situation was to provide a comprehensive library of higher-order primitives. A limited versoin of such a library had been available before, providing efficient versions of higher-order predicates like map/3, foldl/4, filter/3 etc. [...] During the redesign, we soon realised that going beyond these basics would require to consider additional concepts like lambda expressions, composition of higher-order predicats [...] This however, would have conflicted with our initial objective: it was unlikely that anything based on such complex concepts would be readily accepted by novices...
sehr schön 8-)
Ende der 1980-er Jahre haben ein Freund und ich den Gaußschen Algorithmus für die Lösung eines linearen Gleichungssystems in Prolog implementiert: Das war eine echte Herausforderung. Aus dieser Erfahrung habe ich gelernt: Es lohnt sich, eine für das Problem passende Programmiersprache zu wählen.
Das soll nicht heißen, dass ich den Charme des higher-order nicht nachvollziehen könnte. Ich bin mir nur nicht so sicher, dass Schleifen in R generell abgelehnt würden oder auch abgelehnt werden sollten. Und wenn man sich anschaut, wie elegant eine for-Schleife mit dem foreach-Paket parallelisiert werden kann, ist sie auch nicht unbedingt ein Konzept der Vergangenheit.
aber es gibt viele Situationen, in denen die neuen Konstrukte einfach toll sind. Und deshalb muss der Umgang mit diesen Konstrukten frühzeitig geübt werden.
Einerseits ist es eine große Chance, dass Neuling noch nicht durch andere Programmiersprachen verdorben sind
Du hast sicher Recht, dass das Bild einer Sprache von den ersten Schritten geprägt wird und wenn man sich mal mit Schleifen zu helfen weiß, dann ist es eine Hürde, sich andere Konzepte anzuschauen, die man "nicht wirklich braucht".
aktuelles Beispiel von gestern:
Es sollte eine Funktion für das gleitende Arithmetische Mittel programmiert werden.
Frage: Welche Parameter soll die Funktion verarbeiten? Antwort war schnell klar: den Vektor x und den Parameter für Anzahl der Werte für das gleitende Mittel.
Frage: Wie soll das ablaufen? Antwort: for-Schleife
Nach etwas Vorarbeit konnte die Funktion geschrieben werden:

Code: Alles auswählen

    gleitM <- function(x, n=3) {  
      l <- length(x)  
      y <- numeric(l-(n-1))  
      for (j in 1:(l-(n-1))) y[j] <- mean(x[j:(j+(n-1))])  
      return(y)  
    }
Frage von einem Studenten: Wofür brauchen wir y <- numeric(l-(n-1)) ?
Die Frage zeigt, dass auch bei den schönen universellen for-Schleifen einiges zu bedenken ist, was für einen Geübten selbstverständlich ist.

Anschließend eine Version mit sapply()

Code: Alles auswählen

    gleitM2 <- function(x, n=3) {  
      l <- length(x)  
      sapply(1:(l-(n-1)), function(j) mean(x[j:(j+(n-1))]))  
    }
Anschließend gab es noch einen Ausflug zum Paket zoo ...
Wenn die for-Schleifen weniger Gewicht bekommen sollen, dann muss man frühzeitig das Erstellen von Funktionen besprechen.
Das ist eben kontextspezifisch. Wenn Du eine Anzahl X Studenten hast, die sich für einen Kurs verpflichtet haben und den in jedem Fall beenden wollen oder wenn ein User Dein Buch gekauft und dafür Geld ausgegeben hat, dann kannst Du mit abstrakten Konzepten anfangen und darauf bauen, dass deren Nutzen sich später schon noch zeigen wird. Wenn Du mehr so eine lockere Option "wenn Du in der Pause mal Zeit hast" als Unterricht anbietest, oder Dein Schüler nicht Dein Buch sondern Deinen Blog liest, dann kann es wichtiger sein, schnell konkrete Ergebnisse zu produzieren. Hast Du denn einen spezifischen Kontext, für den Du die Frage stellst oder ist das mehr so allgemein philosophisch?
Die Frage ist wirklich konkret gemeint. Weil R höher strukturierte Datenobjekte verarbeiten, ist es angebracht, dabei auch die passenden Arbeitstiere einzusetzen (die apply-Funktionen).
Ich habe eine 8jährige Tochter und habe mir lange die Frage gestellt, welche Programmiersprache ich ihr wohl als erstes zeigen werde. (Zu früh? Ich habe gelesen, die Forschung zeige, dass man Mädchen ganz früh für Computer gewinnen müsse, bevor noch die Assoziation entsteht, Computer seien was für Jungen.) Das klingt jetzt vielleicht nach einer ganz anderen Frage, aber so anders ist die gar nicht. Ein
Sprachenkandidat in meinem Kopf war in der Tat Haskell: Minimalistische Syntax, kein Klammernzählen, kein Semicolon am Zeilenende. Stattdessen klare Konstrukte, Funktionen wie aus der Mathematik, gut REPL-fähig. Eine for-Schleife hätte es da gar nicht gegeben, sodass die Frage sich auch nicht gestellt hätte. Eine Sprache mit mathematischer Schönheit, geeignet um Konzepte anstelle von Syntax zu lernen.
Allein -- da hätte ich Jahre warten müssen, bis die Mathematiklehrer die Konstrukte erklären, die in Haskell so schön wiederzufinden sind.
Stattdessen lernt sie jetzt erstmal Scratch: Da ist nix mit Funktionen, dafür Objekte. Die Objekte sind bunte Bilder und alles ist event-driven. Dafür sind die Kommandos in Deutsch verfübar und man hat ratz-fatz lustige Farbeffekte, bewegte Sprites, Soundeffekte und ein Syntax-Error ist, wenn die Puzzleteile nicht zusammen passen. Motivation durch schnelle Erfolge eben. Was aber ein Datentyp ist, ein Rückgabewert, eine Rekursion oder wiederverwendbarer Code, das wird sie damit sicher nicht lernen. Welche Sprache dafür später herhalten muss und ob sie später überhaupt eine "richtige" Sprache lernen will, weiß ich jetzt noch nicht. Die bunten Kätzchen etc. werden ihr bei der "richtigen" Sprache dann aber fehlen.
Überhaupt erstmal eine Programmiersprache und deren Konzepte zu lernen, macht viel aus. Schon die zweite Programmiersprache lernt sich wesentlich schneller ...
In den 1990-er Jahren wurde auch über LOGO in den ersten Schuljahren berichtet https://de.wikipedia.org/wiki/Logo_(Programmiersprache)
... ha, Scratch ist eine Folgesprache von LOGO https://de.wikipedia.org/wiki/Scratch_( ... ersprache)
Danke für die Frage. Ich finde es schön, wenn hier im Forum nicht nur nach Code gefragt wird sondern beispielsweise auch, wie man R am besten vermittelt. Gerne auch die Frage, ob wir hier im Forum Schleifen für veraltet halten.
Meine Meinung dazu ist:
die for-Schleife ist notwendig in R, aber man kann sie schlecht an den Parameter FUN= in den apply-Funktionen binden. ;)

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

Re: Didaktik in R

Beitrag von bigben »

Hallo Jörg,
jogo hat geschrieben: Di Mai 28, 2019 10:11 amAuf GOTO kann besonders gut verzichtet werden, wenn es wie in R die Konstrukte break und next gibt. [...] Und ganz klar: die for-Schleife ist ein Konstrukt, dass in einigen Situationen nur schwer zu ersetzen ist.
Im Gegenteil: for, break und next sind überflüssige reservierte Wörter, deren Funktion durch IF-GOTO-Konstruktionen mühelos vollständig ersetzt werden kann. Versieht man die GOTOs dann noch mit gut gewählten Sprungmarken-Namen, ist das Ergebnis möglicherweise lesbarer als die drei genannten, die im Falle schlechter Einrückpraxis das Abzählen von geschwieften Klammern erforderlich machen, will man den Programmfluss verstehen... :lol:
Das sind für mich die Programmieren, die weitestgehend einzelne Zahlen und Zeichenketten verarbeiten
Bei meiner weiteren Suche habe ich folgende Text gefunden, der zu Deinem obenstehenden Zitat passt, aber auch meine Zweifel hinsichtlich einer scharfen Abgrenzbarkeit adressiert:
While the definition of 4GL has changed over time, it can be typified by operating more with large collections of information at once rather than focusing on just bits and bytes. Languages claimed to be 4GL may include support for database management, report generation, mathematical optimization, GUI development, or web development. Some researchers state that 4GLs are a subset of domain-specific languages.

The concept of 4GL was developed from the 1970s through the 1990s, overlapping most of the development of 3GL. While 3GLs like C, C++, C#, Java, and JavaScript remain popular for a wide variety of uses, 4GLs as originally defined found narrower uses. Some advanced 3GLs like Python, Ruby, and Perl combine some 4GL abilities within a general-purpose 3GL environment. Also, libraries with 4GL-like features have been developed as add-ons for most popular 3GLs. This has blurred the distinction of 4GL and 3GL.
( https://en.wikipedia.org/wiki/Fourth-ge ... g_language )

aktuelles Beispiel von gestern: [...]

Code: Alles auswählen

    gleitM <- function(x, n=3) {  
      l <- length(x)  
      y <- numeric(l-(n-1))  
      for (j in 1:(l-(n-1))) y[j] <- mean(x[j:(j+(n-1))])  
      return(y)  
    }
Frage von einem Studenten: Wofür brauchen wir y <- numeric(l-(n-1)) ?
Ich finde die Frage dieses Studenten überaus angemessen. Wofür brauchen wir das?

Wir brauchen das erstmal, um die Variable zu deklarieren.

Nehmen wir an ich schreibe:

Code: Alles auswählen

x <- 1
Dann sieht R, dass es bislang keine Variable x gibt, alloziert den benötigten Speicher, erkennt den Datentyp numeric und passt den Namespace an. Und weil jede Variable in R ein Vector ist kann ich schreiben:

Code: Alles auswählen

print(x[1])
und alles ist gut. Schreibe ich aber am Anfang gleich

Code: Alles auswählen

y[1] <- 1
Dann sollte R erkennen, dass es noch keine Variable y gibt, sollte den benötigten Speicher allozieren, den Datentyp erkennen, den Namespace anpassen und den Wert zuweisen. Stattdessen motzt R mit einer Fehlermeldung "object 'y' not found".
Entweder sollte man Variablen vor ihrer Nutzung deklarieren müssen oder nicht. In R muss man es eigentlich nicht, außer wenn man mit `[ darauf zugreifen will, dann muss man es doch. Ist das logisch? Wofür brauchen wir das? Antwort: Wir brauchen das, weil R da verstörende Syntaxregeln hat!

Das Andere was Du mit Deinem y <- numeric(l-(n-1)) erreichst ist die Allokation von ausreichend viel Speicher. Um eine bessere Performance zu erzielen teilst Du Deiner Programmiersprache bei der Variablendeklaration mit, wieviel Speicher Du voraussichtlich brauchen willst. Wie 3G ist das denn bitte? Da sitzt Du also ganz gemütlich in Deiner 4G-Sprache und machst Dir Gedanken, wie unperformant es wäre, wenn die Programmiersprache im Hintergrund ständig mit dem Betriebssystem kommuniziert und den Heap umkrempelt. Wofür brauchen wir das? Antwort, um uns den Grundlagen der Datenverarbeitung zu widmen, die wir mit der höheren Sprache eigentlich wegabstrahieren wollten.
Anschließend eine Version mit sapply()

Code: Alles auswählen

    gleitM2 <- function(x, n=3) {  
      l <- length(x)  
      sapply(1:(l-(n-1)), function(j) mean(x[j:(j+(n-1))]))  
    }
Ehrlich gesagt, finde ich das Beispiel jetzt nicht so viel eleganter und schon gar nicht lesbarer als die for-Variante und schon gar nicht lesbarer, als die for-Variante in meinem Wunsch-R, in dem man den numeric-Aufruf nicht bräuchte. Das gilt aber nur für das Beispiel. Grundsätzlich verstehe ich Dich schon richtig.

die for-Schleife ist notwendig in R, aber man kann sie schlecht an den Parameter FUN= in den apply-Funktionen binden.
Es gibt Sprachen, in denen for eine Funktion ist, beispielsweise for-each in Scheme...

Ehrlich gesagt, bin ich da mit R noch nicht so richtig glücklich: Wenn ich konzeptuell eine Schleife haben will, dann kann ich die Umsetzen als vektorwertige Programmierung, als Schleife, als higher-order function oder in den eckigen Klammern (am mächtigsten in data.table-eckigen Klammern). Ich habe immer irgendwie den Eindruck, es sollte möglich sein, die Syntax von vektorwertiger Programmierung und von higher-order Functions einander näher zu bringen, vielleicht auch Vectorize irgendwie als Infix-Operator oder in einer Form von Pipe oder so anzubieten, oder... Nein, ich habe da weder ein konkretes Konzept noch will ich Sprachenentwickler werden. Ich finde nur, dass es da zu viele Erfindungen des Rades gibt, die aber alle nur auf bestimmten Straßen fahren können.

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: Didaktik in R

Beitrag von jogo »

Hallo Berhard,
bigben hat geschrieben: Di Mai 28, 2019 4:20 pm
jogo hat geschrieben: Di Mai 28, 2019 10:11 amAuf GOTO kann besonders gut verzichtet werden, wenn es wie in R die Konstrukte break und next gibt. [...] Und ganz klar: die for-Schleife ist ein Konstrukt, dass in einigen Situationen nur schwer zu ersetzen ist.
Im Gegenteil: for, break und next sind überflüssige reservierte Wörter, deren Funktion durch IF-GOTO-Konstruktionen mühelos vollständig ersetzt werden kann. Versieht man die GOTOs dann noch mit gut gewählten Sprungmarken-Namen, ist das Ergebnis möglicherweise lesbarer als die drei genannten, die im Falle schlechter Einrückpraxis das Abzählen von geschwieften Klammern erforderlich machen, will man den Programmfluss verstehen... :lol:
ich vermute das ist alles sehr abhängig davon, wie man die Konstrukte einsetzt.
Sicher kann man ohne GOTO grauselig programmieren.
Das sind für mich die Programmieren, die weitestgehend einzelne Zahlen und Zeichenketten verarbeiten
Bei meiner weiteren Suche habe ich folgende Text gefunden, der zu Deinem obenstehenden Zitat passt, aber auch meine Zweifel hinsichtlich einer scharfen Abgrenzbarkeit adressiert:
While the definition of 4GL has changed over time, it can be typified by operating more with large collections of information at once rather than focusing on just bits and bytes. Languages claimed to be 4GL may include support for database management, report generation, mathematical optimization, GUI development, or web development. Some researchers state that 4GLs are a subset of domain-specific languages.

The concept of 4GL was developed from the 1970s through the 1990s, overlapping most of the development of 3GL. While 3GLs like C, C++, C#, Java, and JavaScript remain popular for a wide variety of uses, 4GLs as originally defined found narrower uses. Some advanced 3GLs like Python, Ruby, and Perl combine some 4GL abilities within a general-purpose 3GL environment. Also, libraries with 4GL-like features have been developed as add-ons for most popular 3GLs. This has blurred the distinction of 4GL and 3GL.
( https://en.wikipedia.org/wiki/Fourth-ge ... g_language )
Danke für den Link. Verschiedene Ansichten prägen die Begriffe und Definitionen - alle haben durchaus eine gewisse Berechtigung. Eine klare Abgrenzung ist nicht möglich.

aktuelles Beispiel von gestern: [...]

Code: Alles auswählen

    gleitM <- function(x, n=3) {  
      l <- length(x)  
      y <- numeric(l-(n-1))  
      for (j in 1:(l-(n-1))) y[j] <- mean(x[j:(j+(n-1))])  
      return(y)  
    }
Frage von einem Studenten: Wofür brauchen wir y <- numeric(l-(n-1)) ?
Ich finde die Frage dieses Studenten überaus angemessen. Wofür brauchen wir das?

Wir brauchen das erstmal, um die Variable zu deklarieren.
genau
Ehrlich gesagt, finde ich das Beispiel jetzt nicht so viel eleganter und schon gar nicht lesbarer als die for-Variante und schon gar nicht lesbarer, als die for-Variante in meinem Wunsch-R, in dem man den numeric-Aufruf nicht bräuchte. Das gilt aber nur für das Beispiel. Grundsätzlich verstehe ich Dich schon richtig.
An irgendeiner Stelle muss man aber anfangen, die Möglichkeiten von R darzustellen. In diesem Beispiel ging es nicht darum, dass die eine Variante besser als die andere ist, sondern beide Möglichkeiten sollten dargestellt werden.
Ehrlich gesagt, bin ich da mit R noch nicht so richtig glücklich: ...
Wir sind inzwischen von meiner Frage sehr weit abgekommen.
Es geht nicht um eine Alternative zu R. Die Programmiersprache steht fest: es ist R.
Es geht auch nicht darum, dass man alles, was die apply-Funktionen machen, auch mit for-Schleifen erledigen kann.
Es geht um folgendes:
R hat nun mal diese Funktionen, um die Arbeit mit den höher strukturierten Objekten zu erledigen. Wie kann ich Programmierneulinge an die Nutzung dieser Funktionen heranführen?
Wenn es also Texte gibt, in denen das schön gemacht ist, freue ich mich auf entsprechende Hinweise. Oder wenn jemand selber Erfahrungen hat, was bei dem Vermitteln dieser Funktionen gut oder auch schlecht gelaufen ist, bin ich an diesen Erfahrungen sehr interessiert.

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

Re: Didaktik in R

Beitrag von bigben »

Hallo Jörg,
Wir sind inzwischen von meiner Frage sehr weit abgekommen.
Es geht nicht um eine Alternative zu R. Die Programmiersprache steht fest: es ist R.
Sorry, ich wollte weder das Thema wechseln, noch abschweifen. Ich dachte, dass eine kritische Auseinandersetzung mit dem, was man in R besser oder schlechter findet auch die Schwerpunkte setzen kann, was man wie lehrt und daraus auch die Rechtfertigung gegenüber den Studierenden ableitet.
R hat nun mal diese Funktionen, um die Arbeit mit den höher strukturierten Objekten zu erledigen. Wie kann ich Programmierneuling an die Nutzung dieser Funktionen heranführen?
Ich hatte nach dem Setting gefragt und verstehe jetzt, dass es sich um Studierende handelt und dass Du eine gewisse, nicht zu knappe Zeit hast, das Thema aufzubauen.
Ich glaube, ich würde wahrscheinlich ungewöhnlich einsteigen, nämlich mit replicate. Jeder sieht sofort ein, dass man gewisse Abläufe -Simulationen findet jeder spannend- wiederholen muss und replicate ist von der Syntax schlicht genug, dass man sich an das Übergeben einer Funktion als Argument gewöhnen kann, ohne gleichzeitig weitere Konzepte begreifen zu müssen.

Beispiel: "Wir stellen den zentralen Grenzwertsatz auf die Probe":

Code: Alles auswählen

# Eine Funktion berechnet einen Mittelwert aus n Werten einer 
# absolut nicht normalverteilten Funktion
einmal <- function(n = 50) mean(sample(0:1, n, replace = TRUE))

# Diese Funktion rufen wir jetzt tausenmal auf
tausendmal <- replicate(1000, einmal())

# Und dann schauen wir uns das Histogramm an
hist(tausendmal)
Hier muss man sich noch keine Gedanken um irgendeine Zuordnung machen. In der alternativen for-Schleife müsste man eine Laufvariable definieren, die völlig überflüssig bleibt und deshalb vom Sinn des Codes ablenkt. Deshalb ist das ein Beispiel für eine tatsächlich elegantere Syntax als die zugehörige for-Schleife.

Dann kann man leicht erklären, dass replicate nur für Funktionen interessant ist, die Zufallszahlen verwenden. Das leitet dann ganz leicht über zu der sapply(1:n, ...) Konstruktion, die die "ganz alte for-Schleife" (FOR i = 1 TO 10) ersetzt. Wenn man dann ein paarmal das Muster erlebt hat, dass i immer nur verwendet wird um

Code: Alles auswählen

names[i] 
zu schreiben kann man daraus die "neue for-Schleife" (for(name in names)) als normales sapply einsetzen. Vorteile hier sind eben wieder die Kürze, z. B. weil man nicht explizit die Ergebnisvariable deklarieren muss.

Im Anschluss dann zügig tapply.

Der Masterplan dahinter wäre eben mit einer Konstruktion anzufangen, für die for unnötig komplex wäre, über Konstruktionen zu gehen, die den Hauptanwendungsfall der normalen for-Schleife abdecken und mit tapply etwas ganz offensichtlich sehr nützliches, für das man sich mit for als Anfänger schon ganz schön den Kopf zerbrechen müsste.

Man könnte ja diese Konstrukte der Reihe nach erklären und dann erst hinterher erkläutern, dass es da noch die for-Schleife gibt, die das zwar alles auch kann, die aber aus den o. g. Gründen oft nachteilhaft ist. Dann wäre das erste, womit die Studierenden konfrontiert wären die higher-order functions und die for-Schleife das nachgereichte, dessen Schwächen gleich beim ersten Kontakt bewusst werden.

Ich finde es viel entscheidender und anspruchsvoller, vorher die Einführung von Funktionen gut zu machen. Die for-Schleife anfangs gar nicht zu erwähnen, bis die Studierenden die Schönheit der anderen Funktionen erkannt haben, ist ja einfach nur ein Weglassen. Wenn ein Studierender aber einmal die Wichtigkeit begriffen hat, dass Daten per Argument in die Funktion und per Rückgabewert heraus kommen, dann wird er es in diesem Sinne auch unelegant finden, dass man im for-Block Variablen von Durchführung zu Durchführung verändern kann, ohne deren Einfluss auf den nächsten Blockdurchlauf explizit durch eine Argumentbenennung zu markieren:

Code: Alles auswählen

a <- 0
for (i in 1:10){
  a <- cos(a)
  print(a)
}
Und wenn er die Hässlichkeit dessen erkannt hat, dann kann man ihn auch fragen, wie er das mit higher-order functions schreiben würde und so wird die Rolle, die Du der for-Schleife zugedenkst von Anfang an deutlich.

Spätestens wenn Du dann die Übungsaufgabe verteilst, tapply mittels for nachzuprogrammieren, werden sie for danach instinktiv meiden :lol:

HTH,
Bernhard
---
Programmiere stets so, dass die Maxime Deines Programmierstils Grundlage allgemeiner Gesetzgebung sein könnte
Antworten