In Funktion auf Variable zugreifen

Wie erweitere ich R um eigene Funktionen oder Pakete? Welches Paket ist passend für meine Fragestellung?

Moderatoren: EDi, jogo

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

Re: In Funktion auf Variable zugreifen

Beitrag von bigben »

Hallo anfänger,

mit ein paar kleinen Syntax-Korrekturen und unter zuhilfenahme der Funktion cat sieht das jetzt so aus:

Code: Alles auswählen

mittelwerte <- function(input1, input2, input3){
  mittelwert1 <- mean(input1)
  mittelwert2 <- mean(input2)
  mittelwert3 <- mean(input3)
  
  differenz12 <- mittelwert1 - mittelwert2
  differenz13 <- mittelwert1 - mittelwert3
  
  werte <- cbind(mittelwert1, mittelwert2, mittelwert3)
  differenz <- paste("Die Differenz zwischen Wert 1 & Wert 2 beträgt", differenz12, "\nDie Differenz zwischen Wert 1 und Wert 3 beträgt", differenz13)
  
  return(list("Werte" = werte, "Differenz"=differenz))
}

ergebnis <- mittelwerte(1:3,2:4,3:5)
ergebnis$Differenz
cat(ergebnis$Differenz)

Ich könnte mir vorstellen, dass Du Deiner Funktion mittelwerte eine print-Option hinzufügst. Dann kann der Nutzer gleich bei Aufruf entscheiden, ob das Ergebnis mittels cat ausgegeben werden soll oder in der Version mit \n zur Weiterverwendung in anderen Funktionen bleiben soll. Zum Beispiel:

Code: Alles auswählen

mittelwerte <- function(input1, input2, input3, silent=FALSE){
  mittelwert1 <- mean(input1)
  mittelwert2 <- mean(input2)
  mittelwert3 <- mean(input3)
  
  differenz12 <- mittelwert1 - mittelwert2
  differenz13 <- mittelwert1 - mittelwert3
  
  werte <- cbind(mittelwert1, mittelwert2, mittelwert3)
  differenz <- paste("Die Differenz zwischen Wert 1 & Wert 2 beträgt", differenz12, "\nDie Differenz zwischen Wert 1 und Wert 3 beträgt", differenz13)
  
  if(!silent) {cat(differenz); cat("\n")}
  
  return(list("Werte" = werte, "Differenz"=differenz))
}

ergebnis <- mittelwerte(1:3, 2:4, 3:5)
ergebnis <- mittelwerte(1:3, 2:4, 3:5, silent = TRUE)
Eine Lösung für Fortgeschrittene wäre objektorientierte Programmierung. Du schaffst eine Objektklasse für mittelwerte-Ergebnisse und kannst Du eine eigene print-Funktion für Objekte dieser Klasse definieren:

Code: Alles auswählen

mittelwerte <- function(input1, input2, input3){
  mittelwert1 <- mean(input1)
  mittelwert2 <- mean(input2)
  mittelwert3 <- mean(input3)
  
  differenz12 <- mittelwert1 - mittelwert2
  differenz13 <- mittelwert1 - mittelwert3
  
  werte <- cbind(mittelwert1, mittelwert2, mittelwert3)
  differenz <- paste("Die Differenz zwischen Wert 1 & Wert 2 beträgt", differenz12, "\nDie Differenz zwischen Wert 1 und Wert 3 beträgt", differenz13)
  
  result <- list("Werte" = werte, "Differenz"=differenz)
  class(result) <- "mwresult"
  
  return(result)
}

print.mwresult <- function(r) {
  cat("Ergebnis eines dreifachen Mittelwertvergleichs:\n")
  cat("Mittelwerte:\n")
  cat(r[[1]])
  cat("\nFreitext:\n")
  cat(r[[2]])
  cat("Ergebnis zuende\n\n")
}

ergebnis <- mittelwerte(1:3, 2:4, 3:5)
ergebnis
LG,
Bernhard
---
Programmiere stets so, dass die Maxime Deines Programmierstils Grundlage allgemeiner Gesetzgebung sein könnte
jogo
Beiträge: 2086
Registriert: Fr Okt 07, 2016 8:25 am

Re: In Funktion auf Variable zugreifen

Beitrag von jogo »

Hallo anfänger,
anfänger hat geschrieben: Mo Mai 04, 2020 12:21 pm Danke für eure Antworten.

"Notwendig" ist dieses Verhalten nicht. Ist wohl eher ein "optisches" Problem. Weil ein Ergebnis "schöner" über mehrere Zeilen, als in einer Zeile präsentiert werden kann.

Hier ein stark vereinfachtes Beispiel: Ich habe eine Funktion, welche mir für verschiedene Inputvariablen den Mittelwert und die Differenz zwischen den Mittelwerten berechnet

Code: Alles auswählen

mittelwerte <- function(input1, input2, input3){...
}
also etwa so:

Code: Alles auswählen

mittelwerte <- function(input1, input2, input3){
  mittelwert1 <- mean(input1)
  mittelwert2 <- mean(input2)
  mittelwert3 <- mean(input3)
  
  differenz12 <- mittelwert1 - mittelwert2
  differenz13 <- mittelwert1 - mittelwert3
  
  werte <- cbind(mittelwert1, mittelwert2, mittelwert3)
  differenz <- paste("Die Differenz zwischen Wert 1 & Wert 2 beträgt", differenz12, "\nDie Differenz zwischen Wert 1 und Wert 3 beträgt", differenz13)
  
  list("Werte" = werte, "Differenz"=differenz)
}
ergebnis <- mittelwerte(1:3, 2:4, 3:5)
cat(ergebnis$Differenz)
Anmerkungen zu Deinem Code:
return() ist eine Funktion in R - es ist mindestens für andere verwirrend, wenn Du eigene Objekte so nennst, wie vorhandenen R-Funktionen.
In diesem Fall ist es obsolet, weil wenn kein expliziter Aufruf von return() in einer Funktion erfolgt, dann wir einfach der zuletzt berechnete Wert zurückgeliefert.

Ist natürlich jetzt kein besonders wertvolles Beispiel, da recht simpel, aber ich denke es veranschaulicht das "Problem".
Ziel wäre es jetzt durch:

Code: Alles auswählen

ergebnis <- mittelwert(1:3,2:4,3:5)
ergebnis$differenz
Ein Ergebnis zu erhalten, welches den Zeilenumbruch enthält.

Klar, man könnte es durch cat(ergebnis$differenz) lösen, das würde aber voraussetzen, dass jeder Nutzer der Funktion (wenn man weiter denkt) wissen müsste, dass er hier ein cat() setzen muss.
Ich hab's jetzt mit einer "Tabelle" also cbind() gelöst, gefällt mir nicht so gut, ist aber i.O.
Bedenke aber auch, dass Du Berechnung und Druckaufbereitung miteinander verquicken möchtest.
Wenn es eine Erfüllung Deines Wunsches gibt, dann bedeutet das auch, dass jeder Nutzer der Funktion an genau diese Druckaufbereitung gebunden ist. Nach meinen ca. 40 Jahren Programmiererfahrung ist es nützlich, das Berechnen der Ergebnisse von der Aufbereitung des Outputs zu trennen.
Falls dieses "Problem" und meine Frage in diesem Forum hier jetzt unpassend oder nicht gewollt ist, tut es mir leid. Allerdings war ich der Meinung, dass man dieses "Problem" eines mehrzeiligen Returns aus einer Funktion doch irgendwie lösen können muss. Google hat mir nicht geholfen, deshalb die Nachfrage. Falls unpassend -> Sorry!
also unpassend würde ich es mit dem jetzigen Beispiel nicht unbedingt nennen.
Die Fragestellung ist aber ungewöhnlich, weil sich das gewünschte Verhalten im allgemeinen eher als hinderlich statt nützlich herausstellt.
Der Wunsch nach einem mehrzeiligen output bedeuet, dass es um Druckaufbereitung geht.
Du könntest Dir eine eigene Pseudoklasse .myout definieren. In jedem Objekt dieser Pseudoklasse gibt eine Listenelement $out.
Die passende Funktion print.myout(...) nimmt dann dieses Listenelement und macht die Druckaufbereitung z.B. mit cat() o.ä.
(print() wird immer dann im interaktiven Modus aufgerufen, wenn das Ergebniss der Berechnung eines Ausdrucks nicht zugewiesen wird.)

Meine ganz persönliche Meinung zu dieser Idee: mir wäre der Aufwand der Umsetzung die Mühe nicht wert.

Gruß, Jörg
anfänger
Beiträge: 6
Registriert: Fr Mai 01, 2020 7:24 pm

Re: In Funktion auf Variable zugreifen

Beitrag von anfänger »

Danke euch!

Werde die verschiedenen Lösungsansätze mal umsetzen und schauen, wie es mir gefällt. Danke für die Tipps und Hinweise.

Objektorientierung geht für mich momentan noch einen Schritt zu weit, ist aber natürlich eine interessante Option. Für diesen Zweck aber dann doch eher den Aufwand nicht wert.
Antworten