Dplyr joindre par=(a = b), où a et b sont des variables contenant des chaînes de caractères?
Je suis en train d'effectuer une jointure de deux tables à l'aide de dplyr, et je pense que je suis fauché par des non-standard des règles d'évaluation. Lors de l'utilisation de la par=("a" = "b") argument, tout fonctionne comme prévu lorsque "a" et "b" sont des chaînes de caractères. Voici un exemple jouet qui fonctionne:
library(dplyr)
data(iris)
inner_join(iris, iris, by=c("Sepal.Length" = "Sepal.Width"))
Mais disons que je met inner_join dans une fonction:
library(dplyr)
data(iris)
myfn <- function(xname, yname) {
data(iris)
inner_join(iris, iris, by=c(xname = yname))
}
myfn("Sepal.Length", "Sepal.Width")
Renvoie le message d'erreur suivant:
Error: cannot join on columns 'xname' x 'Sepal.Width': index out of bounds
Je soupçonne qu'il ya un peu de fantaisie expression, deparsing, citant, ou unquoting que je pourrais faire pour faire ce travail, mais je suis un peu trouble sur ces détails.
- Hadley appelle cette "non-standard d'évaluation" (NSE)
- Semble pas tellement NSE que la prestation de la "en.x" et "par.y" les noms de colonne dans une manière différente. Le
by
-argument devientc("Sepal.Length" = "Sepal.Width")
et donc ce serait laby.x
argumentmerge
devient un réel R nom. En fait, c'est presque à l'opposé du NSE comme je l'ai vue il.
Vous devez vous connecter pour publier un commentaire.
Vous pouvez utiliser
L'a suggéré la syntaxe dans le
?inner_join
documentation deest un peu trompeur parce que ces deux valeurs ne sont pas des valeurs de caractère. Vous êtes en train de créé un personnage nommé vecteur. Pour définir dynamiquement les valeurs de la gauche du signe égal est différent de ceux de droite. Vous pouvez utiliser
setNames()
pour définir les noms du vecteur dynamique.setNames
, l'ordre des arguments est inversé par rapport à l'original une utilisation dansinner_join
. Pour avoir le même ordre de l'argumentation, c'est à dire d'abordxname
puisyname
, vous pouvez utiliserby=setNames(nm=xname, yname)
.Je sais je suis en retard à la fête, mais que diriez-vous:
De cette façon, vous pouvez faire ce que vous voulez avec:
myfn(c("a" = "b", "c" = "d"))
quemyfn(c("a", "c"), c("b", "d"))
, mais c'est une question de goût j'imagine.myfn(c(a = "b", c = "d"))
, et à mes yeux ce serait encore plus clair car il utilise l'habitude de saisie des noms, pour ne pas mentionner moins de caractères qui ont besoin d'un changement de clé.J'ai fait face à presque le même défi que @Peter, mais il faut passer plusieurs ensembles différents de
by =
rejoindre paramètres en une seule fois. J'ai choisi d'utiliser lemap()
fonction de la tidyverse paquet,purrr
.C'est le sous-ensemble de la tidyverse que j'ai utilisé.
Tout d'abord, j'ai adapté
myfn
à utilisermap()
pour le cas publié par Pierre. 42 commentaire et Felipe Gerard réponse il est clair que laby
argument peut prendre un nom de vecteur.map()
nécessite une liste sur laquelle l'itération.J'ai constaté que je n'avais pas besoin de
quo_name()
/!!
dans la construction de la fonction.Puis, je me suis adapté à la fonction de prendre une liste de
by
paramètres. Pour chaqueby_i
dansby_grps
, nous pourrions étendrex
ety
pour ajouter des valeurs nommées sur pour rejoindre.J'aime MrFlick la réponse de fber additif, mais je préfère
structure
. Pour moisetNames
se sent comme quelque chose à la fin d'une pipe, pas comme à la volée constructeur. Sur une autre note, à la foissetNames
etstructure
permettre l'utilisation de variables dans l'appel de fonction.Un nommé vecteur argument serait confronté à des problèmes ici:
Vous pourriez résoudre, même si, en utilisant
setNames
oustructure
dans l'appel de fonction.