2015-02-08 6 views
20

Sto cercando di eseguire un inner join su due tabelle usando dplyr, e penso di essere bloccato da regole di valutazione non standard. Quando si utilizza l'argomento by = ("a" = "b"), tutto funziona come previsto quando "a" e "b" sono stringhe reali. Ecco un esempio giocattolo che funziona:Dplyr join on = (a = b), dove a e b sono variabili contenenti stringhe?

library(dplyr) 
data(iris) 

inner_join(iris, iris, by=c("Sepal.Length" = "Sepal.Width")) 

Ma diciamo che stavo mettendo inner_join in una funzione:

library(dplyr) 
data(iris) 

myfn <- function(xname, yname) { 
    data(iris) 
    inner_join(iris, iris, by=c(xname = yname)) 
} 

myfn("Sepal.Length", "Sepal.Width") 

Ciò restituisce il seguente errore:

Error: cannot join on columns 'xname' x 'Sepal.Width': index out of bounds

Sospetto che ci è un'espressione di fantasia, deparabile, citante o non quotata che potrei fare per farlo funzionare, ma sono un po 'torbido su quei dettagli.

+0

Hadley chiama questa [ "valutazione non standard "] (http://adv-r.had.co.nz/Computing-on-the-language.html) (NSE) – smci

+0

Sembra non tanto NSE quanto fornire" by.x "e" by.y " nomi di colonne in un modo diverso. L'argomento 'by' diventa' c ("Sepal.Length" = "Sepal.Width") 'e quindi quale sarebbe l'argomento' by.x' su 'merge' diventa un vero nome R. In effetti è quasi l'opposto di NSE come lo vedo. –

risposta

21

È possibile utilizzare

myfn <- function(xname, yname) { 
    data(iris) 
    inner_join(iris, iris, by=setNames(yname, xname)) 
} 

Il suggerito di sintassi nel ?inner_join documentazione dei

by = c("a"="b") # same as by = c(a="b") 

è leggermente fuorviante perché entrambi questi valori non sono valori carattere proprio. In realtà hai creato un vettore di caratteri con nome. Per impostare dinamicamente i valori a sinistra del segno di uguale è diverso da quelli sulla destra. È possibile utilizzare setNames() per impostare i nomi del vettore in modo dinamico.

+1

Si noti che usando 'setNames', l'ordine degli argomenti è invertito rispetto all'uso originale in' inner_join'. Per avere lo stesso ordine degli argomenti, vale a dire prima 'xname' poi' yname', potresti usare 'by = setNames (nm = xname, yname)'. – fber

2

So di essere in ritardo alla festa, ma come circa:

myfn <- function(byvar) { 
    data(iris) 
    inner_join(iris, iris, by=byvar) 
} 

questo modo si può fare quello che vuoi con:

myfn(c("Sepal.Length"="Sepal.Width")) 
+0

Non è così sostanzialmente diverso dalla risposta MrFlick. –

+0

Sono molto simili. L'unica differenza è quando ti unisci a più dimensioni. Penso che sia più chiaro fare 'myfn (c (" a "=" b "," c "=" d "))' di 'myfn (c (" a "," c "), c (" b ", "d")) ', ma è una questione di gusti, immagino. –

+0

Sì. Posso capire il tuo punto di vista. Comunque stai usando virgolette ridondanti. Puoi chiamare il tuo con 'myfn (c (a =" b ", c =" d "))', e ai miei occhi sarebbe ancora più chiaro dato che usa la solita voce dei nomi, per non parlare di un minor numero di caratteri che bisogno di una chiave di selezione. –