Funktionen auf höherer Ebene in R - Gibt es einen offiziellen Komponierungsbetreiber oder eine Curry -Funktion?
-
19-09-2019 - |
Frage
Ich kann einen Kompose -Operator in R erstellen:
`%c%` = function(x,y)function(...)x(y(...))
So verwendet werden:
> numericNull = is.null %c% numeric
> numericNull(myVec)
[2] TRUE FALSE
Aber ich würde gerne wissen, ob es offizielle Funktionen gibt, die so etwas und andere Operationen wie Currying in R durchführen, vor allem die Anzahl der Klammern, Funktionsschlüsselwörter usw. in meinem Code reduzieren.
Meine Curry -Funktion:
> curry=function(...){
z1=z0=substitute(...);z1[1]=call("list");
function(...){do.call(as.character(z0[[1]]),
as.list(c(eval(z1),list(...))))}}
> p = curry(paste(collapse=""))
> p(letters[1:10])
[1] "abcdefghij"
Dies ist besonders schön für z. B. Aggregat:
> df = data.frame(l=sample(1:3,10,rep=TRUE), t=letters[1:10])
> aggregate(df$t,df["l"],curry(paste(collapse="")) %c% toupper)
l x
1 1 ADG
2 2 BCH
3 3 EFIJ
Was ich viel eleganter und bearbeitbarer finde als:
> aggregate(df$t, df["l"], function(x)paste(collapse="",toupper(x)))
l x
1 1 ADG
2 2 BCH
3 3 EFIJ
Grundsätzlich möchte ich es wissen - wurde dies bereits für R getan?
Lösung
Der Standardplatz für die funktionale Programmierung in R ist jetzt die functional
Bibliothek.
Aus der Bibliothek:
Funktional: Curry, Komponieren und andere Funktionen höherer Ordnung
Beispiel:
library(functional)
newfunc <- Curry(oldfunc,x=5)
Kran:https://cran.r-project.org/web/packages/functional/index.html
PS: Diese Bibliothek ersetzt die ROxigen
Bibliothek.
Andere Tipps
Beide Funktionen existieren tatsächlich in das roxygen
Paket (Siehe den Quellcode hier) von Peter Dänitätsberg (basiert ursprünglich auf Byron Ellis 'Lösung auf R-Help):
Curry <- function(FUN,...) {
.orig = list(...);
function(...) do.call(FUN,c(.orig,list(...)))
}
Compose <- function(...) {
fs <- list(...)
function(...) Reduce(function(x, f) f(x),
fs,
...)
}
Beachten Sie die Verwendung des Reduce
Funktion, die sehr hilfreich sein kann, wenn Sie versuchen, funktionale Programmierung in R zu machen, siehe. Reduzieren Sie für weitere Details (was auch andere Funktionen wie z. Map
und Filter
).
Und Ihr Beispiel für Curry (etwas anders in dieser Verwendung):
> library(roxygen)
> p <- Curry(paste, collapse="")
> p(letters[1:10])
[1] "abcdefghij"
Hier ist ein Beispiel, um den Nutzen von zu zeigen Compose
(Anwenden von drei verschiedenen Funktionen auf Buchstaben):
> Compose(function(x) x[length(x):1], Curry(paste, collapse=""), toupper)(letters)
[1] "ZYXWVUTSRQPONMLKJIHGFEDCBA"
Und Ihr letztes Beispiel würde so funktionieren:
> aggregate(df[,"t"], df["l"], Compose(Curry(paste, collapse=""), toupper))
l x
1 1 ABG
2 2 DEFH
3 3 CIJ
Zuletzt hier ist eine Möglichkeit, dasselbe mitzumachen plyr
(könnte auch leicht mit erledigt werden by
oder aggregate
Wie bereits gezeigt):
> library(plyr)
> ddply(df, .(l), function(df) paste(toupper(df[,"t"]), collapse=""))
l V1
1 1 ABG
2 2 DEFH
3 3 CIJ
Es gibt eine Funktion namens Curry in der Roxygen Paket.
VIV VIV dieses Gespräch Auf dem R -Mail -Archiv.
Ein komplexerer Ansatz ist erforderlich, wenn Sie möchten, dass die "Namen" der Variablen genau durchlaufen.
Zum Beispiel, wenn Sie dies tun plot(rnorm(1000),rnorm(1000))
Dann erhalten Sie schöne Etiketten auf Ihren X- und Y-Achsen. Ein weiteres Beispiel dafür ist data.frame
> data.frame( rnorm(5), rnorm(5), first=rpois(5,1), second=rbinom(5,1,0.5) )
rnorm.5. rnorm.5..1 first second
1 0.1964190 -0.2949770 0 0
2 0.4750665 0.8849750 1 0
3 -0.7829424 0.4174636 2 0
4 1.6551403 1.3547863 0 1
5 1.4044107 -0.4216046 0 0
Nicht, dass der Daten.Frame den Spalten nützliche Namen zugewiesen hat.
Einige Implementierungen von Curry tun dies möglicherweise nicht ordnungsgemäß, was zu unlesbaren Spaltennamen und Handlungsbezeichnungen führt. Stattdessen benutze ich jetzt so etwas:
Curry <- function(FUN, ...) {
.orig = match.call()
.orig[[1]] <- NULL # Remove first item, which matches Curry
.orig[[1]] <- NULL # Remove another item, which matches FUN
function(...) {
.inner = match.call()
.inner[[1]] <- NULL # Remove first item, which matches Curry
do.call(FUN, c(.orig, .inner), envir=parent.frame())
}
}
Das ist ziemlich komplex, aber ich denke, es ist richtig. match.call
Ich werde alle Argumente fangen und sich voll und ganz daran erinnern, welche Ausdrücke die Argumente definiert haben (dies ist für schöne Beschriftungen erforderlich). Das Problem ist, dass es zu viele Argumentationen fängt - nicht nur das ...
aber auch die FUN
. Es erinnert sich auch an den Namen der Funktion, die aufgerufen wird ((Curry
).
Daher möchten wir diese ersten beiden Einträge in löschen .orig
so dass .orig
entspricht wirklich dem ...
Argumente. Deshalb tun wir .orig[[1]]<-NULL
Zweimal - jedes Mal löscht und verschiebt alles andere nach links.
Dies vervollständigt die Definition und wir können jetzt Folgendes tun, um zu bekommen exakt das gleiche wie oben
Curry(data.frame, rnorm(5), rnorm(5) )( first=rpois(5,1) , second=rbinom(5,1,0.5) )
Eine letzte Notiz zu envir=parent.frame()
. Ich habe dies verwendet, um sicherzustellen, dass es kein Problem gibt, wenn Sie externe Variablen namens '.inner' oder '.Orig' haben. Jetzt werden alle Variablen an der Stelle bewertet, an der das Curry aufgerufen wird.