Domanda

posso creare un operatore di composizione in R:

 `%c%` = function(x,y)function(...)x(y(...)) 

Per essere utilizzato in questo modo:

 > numericNull = is.null %c% numeric
 > numericNull(myVec)
 [2] TRUE FALSE

ma mi piacerebbe sapere se c'è un set ufficiale di funzioni per fare questo genere di cose e di altre operazioni come currying in R. In gran parte si tratta di ridurre il numero di staffe, le parole chiave di funzione, ecc nel mio codice.

La mia funzione curry:

> 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"

Questo è particolarmente piacevole per esempio aggregata:

> 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

Il che sembra molto più elegante e modificabile a:

> aggregate(df$t, df["l"], function(x)paste(collapse="",toupper(x)))
  l    x
1 1  ADG
2 2  BCH
3 3 EFIJ

In sostanza vorrei sapere -? È presente già stato fatto per R

È stato utile?

Soluzione

Il luogo standard per la programmazione funzionale in R è ora la libreria functional.

Dalla libreria:

  

funzionale: curry, comporre, e altre funzioni di ordine superiore

Esempio:

   library(functional)
   newfunc <- Curry(oldfunc,x=5)

CRAN: https://cran.r-project.org/web/packages/functional /index.html

PS: Questa libreria sostituisce la libreria ROxigen

.

Altri suggerimenti

Entrambe queste funzioni esiste effettivamente in pacchetto roxygen ( vedere il codice sorgente qui ) da Peter Danenberg (originariamente sulla base di La soluzione di Byron Ellis su R-Aiuto ):

Curry <- function(FUN,...) {
  .orig = list(...);
  function(...) do.call(FUN,c(.orig,list(...)))
}

Compose <- function(...) {
  fs <- list(...)
  function(...) Reduce(function(x, f) f(x),
                       fs,
                       ...)
}

Si noti l'utilizzo della funzione Reduce, che può essere molto utile quando si cerca di fare programmazione funzionale in R. Vedi? Ridurre per maggiori dettagli (che copre anche altre funzioni come Map e Filter).

E il vostro esempio di Curry (leggermente diverso in questo uso):

> library(roxygen)
> p <- Curry(paste, collapse="")
> p(letters[1:10])
[1] "abcdefghij"

Ecco un esempio per mostrare l'utilità di Compose (applicazione di tre funzioni diverse lettere):

> Compose(function(x) x[length(x):1], Curry(paste, collapse=""), toupper)(letters)
[1] "ZYXWVUTSRQPONMLKJIHGFEDCBA"

E il tuo ultimo esempio dovrebbe funzionare in questo modo:

> aggregate(df[,"t"], df["l"], Compose(Curry(paste, collapse=""), toupper))
  l    x
1 1  ABG
2 2 DEFH
3 3  CIJ

Infine, ecco un modo per fare la stessa cosa con plyr (potrebbe facilmente essere fatto con by o aggregate come già evidenziato):

> library(plyr)
> ddply(df, .(l), function(df) paste(toupper(df[,"t"]), collapse=""))
  l   V1
1 1  ABG
2 2 DEFH
3 3  CIJ

C'è una funzione chiamata Curry nel roxygen pacchetto.
Trovato tramite questa conversazione sulla R Mail Archive.

Un approccio più complesso è necessario se si desidera che i 'nomi' delle variabili di passare attraverso con precisione.

Ad esempio, se si plot(rnorm(1000),rnorm(1000)) allora si otterrà belle etichette sul vostro x ed assi y-. Un altro esempio di questo è 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

Non che il data.frame ha assegnato i nomi utili alle colonne.

Alcune implementazioni di Curry non possono farlo correttamente, portando a nomi di colonna e le etichette illeggibili trama. Invece, io uso qualcosa di simile:

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())
    }
}

Questo è abbastanza complesso, ma penso che sia corretto. match.call prenderà tutte args, completamente ricordando ciò che espressioni definite le args (ciò è necessario per belle etichette). Il problema è che si prende troppe args - non solo la ... ma anche il FUN. Si ricorda anche il nome della funzione che viene chiamata (Curry).

Pertanto, vogliamo eliminare queste prime due voci in modo che .orig .orig realtà solo corrisponde agli argomenti .... Ecco perché facciamo .orig[[1]]<-NULL due volte -. Ogni volta che elimina una voce e sposta tutto il resto a sinistra

Questo completa la definizione e ora possiamo procedere come segue per ottenere esattamente lo stesso come sopra

Curry(data.frame, rnorm(5), rnorm(5) )( first=rpois(5,1) , second=rbinom(5,1,0.5) )

Una nota finale sulla envir=parent.frame(). Ho usato questo per garantire che non ci sarà un problema se si dispone di variabili esterne chiamate '.inner' o '.orig'. Ora, tutte le variabili vengono valutate nel luogo in cui il curry è chiamato.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top