2012-11-13 7 views
14

C'è un modo per scrivere le funzioni pipeline in R dove il risultato di una funzione passa immediatamente al successivo? Vengo da F # e ho davvero apprezzato questa abilità ma non ho trovato come farlo in R. Dovrebbe essere semplice ma non riesco a trovare come. In F # sarebbe simile a questa:R Funzioni di pipeline

let complexFunction x = 
    x |> square 
    |> add 5 
    |> toString 

In questo caso l'input sarebbe al quadrato, quindi avere 5 aggiunto ad esso e poi convertito in una stringa. Sto volendo essere in grado di fare qualcosa di simile in R ma non so come. Ho cercato come fare qualcosa di simile ma non ho trovato nulla. Sto volendo questo per l'importazione di dati perché in genere devo importarlo e quindi filtrare. In questo momento lo faccio in più passaggi e mi piacerebbe davvero essere in grado di fare qualcosa come in F # con le condotte.

+1

Non sono abbastanza chiaro su cosa stai chiedendo: 'complexFunction <- function (x) {x <- x^2; x <- x + 5; x <- as.character (x); return (x)} –

+1

Eventuale duplicato: http://stackoverflow.com/questions/7290947/data-manipulation-in-r-in-linq- style – Owen

+0

possibile duplicato di [come implementare l'operatore di pipe forward di F # in R? ] (http://stackoverflow.com/questions/8896820/how-to-implement-fs-forward-pipe-operator-in-r) –

risposta

7

Possiamo usare Compose dal pacchetto funzionale di creare il nostro operatore binario che fa qualcosa di simile a ciò che si vuole

# Define our helper functions 
square <- function(x){x^2} 
add5 <- function(x){x + 5} 

# functional contains Compose 
library(functional) 

# Define our binary operator 
"%|>%" <- Compose 

# Create our complexFunction by 'piping' our functions 
complexFunction <- square %|>% add5 %|>% as.character 
complexFunction(1:5) 
#[1] "6" "9" "14" "21" "30" 


# previously had this until flodel pointed out 
# that the above was sufficient 
#"%|>%" <- function(fun1, fun2){ Compose(fun1, fun2) } 

credo che potremmo tecnicamente fai questo senza richiedere il pacchetto funzionale, ma è così giusto usare Compose per questa attività.

"%|>%" <- function(fun1, fun2){ 
    function(x){fun2(fun1(x))} 
} 
complexFunction <- square %|>% add5 %|>% as.character 
complexFunction(1:5) 
#[1] "6" "9" "14" "21" "30" 
+0

Possiamo sbarazzarci dei due '%%' symbl in '% |> % '? Sembrano brutti e ingombranti. O c'è qualche particolarità per il %% in R? Non riesco a trovare spiegazioni nella documentazione. – Nick

+0

Sono obbligatori. Non so dove sia menzionato nella documentazione su come definire queste cose, ma è lì da qualche parte. Gli operatori di infissi binari definiti dall'utente avranno sempre la forma '% qualcosa%' – Dason

5

Penso che potresti semplicemente voler scrivere una funzione per eseguire i passaggi che desideri.

complexFunction <- function(x) { 
    as.character(x^2 + 5) 
} 

Quindi chiamare solo complexFunction(x).


Modifica per mostrare ciò che R sta facendo internamente (@mnel) - Il modo in cui R analizza e valuta la as.character(x^2 + 5) fa ciò che si vuole

È possibile utilizzare codetools per indagare su ciò che R per vedere come i valori vengono passati a vicenda

flattenAssignment(quote(as.character(x^2+5))) 
[[1]] 
[[1]][[1]] 
x 

[[1]][[2]] 
`*tmp*`^2 

[[1]][[3]] 
`*tmp*` + 5 


[[2]] 
[[2]][[1]] 
`as.character<-`(`*tmp*`, value = `*tmpv*`) 

[[2]][[2]] 
`+<-`(`*tmp*`, 5, value = `*tmpv*`) 

[[2]][[3]] 
`^<-`(x, 2, value = `*tmpv*`) 

o si può ottenere la rappresentazione stile Lisp per vedere come si è analizzato (ed i risultati p assed)

showTree(quote(as.character(x^2+5))) 
(as.character (+ (^ x 2) 5)) 
8

Ecco un approccio di programmazione funzionale che utilizza Reduce. Si tratta infatti di un esempio da ?Reduce

square <- function(x) x^2 
add_5 <- function(x) x+5 
x <- 1:5 
## Iterative function application: 
Funcall <- function(f, ...) f(...) 

Reduce(Funcall, list(as.character, add_5, square,x), right = TRUE) 
## [1] "6" "9" "14" "21" "30" 

o anche più semplicemente utilizzando il pacchetto functional e Compose

Questo è bello come si creerà la funzione per voi

library(functional) 
do_stuff <- Compose(square,add_5,as.character) 
do_stuff(1:5) 
## [1] "6" "9" "14" "21" "30" 

Ho notato che non considererei nessuna di queste app scarafaggi idiomaticamente R ish (se questo è anche una frase)

0

Questo funziona per R abbastanza simile in F #:

"%|>%" <- function(x, fun){ 
    if(is.function(x)) { 
     function(...) fun(x(...)) 
    } else { 
     fun(x) 
    } 
} 
0

Dal momento che questa domanda è stato chiesto, il tubo magrittr è diventato enormemente popolare in R. Così il vostro esempio può essere:

library (magrittr) 

fx <- function (x) { 
    x %>% 
    `^` (2) %>% 
    `+` (5) %>% 
    as.character() 
    } 

Si noti che la notazione di backquote è perché sto letteralmente usando le funzioni built-in di R e ho bisogno di citarle appositamente per usarle in questo modo. Più funzioni di nome normale (come exp o se avessi creato una funzione di supporto add) non avrebbero bisogno di backquote e sarebbero più simili al tuo esempio.

Nota anche che %>% passa automaticamente il valore in ingresso come primo argomento alla funzione successiva, sebbene sia possibile modificarlo. Si noti inoltre che una funzione R restituisce l'ultimo valore calcolato, quindi non è necessario specificare return o assegnare il calcolo per restituirlo.

Questo è molto simile ai buoni operatori speciali definiti da altre risposte, ma utilizza una funzione particolare che è ampiamente utilizzata in R ora.