Cette réponse couvrira la plupart des éléments des réponses existantes, mais cette question (passer les noms de colonnes aux fonctions) se pose assez souvent pour que je veuille qu'il y ait une réponse qui couvre les choses de manière un peu plus complète.
Supposons que nous ayons un cadre de données très simple :
dat <- data.frame(x = 1:4,
y = 5:8)
et nous aimerions écrire une fonction qui crée une nouvelle colonne z
qui est la somme des colonnes x
y y
.
La pierre d'achoppement la plus fréquente est qu'une tentative naturelle (mais incorrecte) ressemble souvent à ceci :
foo <- function(df,col_name,col1,col2){
df$col_name <- df$col1 + df$col2
df
}
#Call foo() like this:
foo(dat,z,x,y)
Le problème est que df$col1
n'évalue pas l'expression col1
. Il recherche simplement une colonne dans df
littéralement appelé col1
. Ce comportement est décrit dans ?Extract
dans la section "Objets récursifs (de type liste)".
La solution la plus simple, et la plus souvent recommandée, est de passer de $
a [[
et transmet les arguments de la fonction sous forme de chaînes de caractères :
new_column1 <- function(df,col_name,col1,col2){
#Create new column col_name as sum of col1 and col2
df[[col_name]] <- df[[col1]] + df[[col2]]
df
}
> new_column1(dat,"z","x","y")
x y z
1 1 5 6
2 2 6 8
3 3 7 10
4 4 8 12
Cette méthode est souvent considérée comme la "meilleure pratique", car c'est celle qui présente le plus de risques d'erreurs. Transmettre les noms de colonnes sous forme de chaînes de caractères est à peu près aussi peu ambigu que possible.
Les deux options suivantes sont plus avancées. De nombreux logiciels courants utilisent ce type de techniques, mais en les utilisant, il est possible d'obtenir des informations plus précises. bien nécessitent plus de soin et de compétence, car elles peuvent introduire des complexités subtiles et des points de défaillance imprévus. Le présent du livre Advanced R de Hadley est une excellente référence pour certaines de ces questions.
Si vous vraiment veulent éviter à l'utilisateur de taper tous ces guillemets, une option pourrait être de convertir les noms de colonnes nus, sans guillemets, en chaînes de caractères à l'aide de l'option deparse(substitute())
:
new_column2 <- function(df,col_name,col1,col2){
col_name <- deparse(substitute(col_name))
col1 <- deparse(substitute(col1))
col2 <- deparse(substitute(col2))
df[[col_name]] <- df[[col1]] + df[[col2]]
df
}
> new_column2(dat,z,x,y)
x y z
1 1 5 6
2 2 6 8
3 3 7 10
4 4 8 12
C'est franchement un peu stupide, puisque nous faisons en réalité la même chose qu'en new_column1
mais avec un travail supplémentaire pour convertir les noms nus en chaînes de caractères.
Enfin, si nous voulons obtenir vraiment Nous pourrions décider qu'au lieu de transmettre les noms des deux colonnes à ajouter, nous aimerions être plus flexibles et permettre d'autres combinaisons de deux variables. Dans ce cas, nous aurons probablement recours à l'utilisation de eval()
sur une expression impliquant les deux colonnes :
new_column3 <- function(df,col_name,expr){
col_name <- deparse(substitute(col_name))
df[[col_name]] <- eval(substitute(expr),df,parent.frame())
df
}
Pour le plaisir, j'utilise toujours deparse(substitute())
pour le nom de la nouvelle colonne. Ici, tous les éléments suivants fonctionneront :
> new_column3(dat,z,x+y)
x y z
1 1 5 6
2 2 6 8
3 3 7 10
4 4 8 12
> new_column3(dat,z,x-y)
x y z
1 1 5 -4
2 2 6 -4
3 3 7 -4
4 4 8 -4
> new_column3(dat,z,x*y)
x y z
1 1 5 5
2 2 6 12
3 3 7 21
4 4 8 32
En résumé, la réponse est la suivante : passez les noms des colonnes de data.frame sous forme de chaînes de caractères et utilisez [[
pour sélectionner une seule colonne. Ce n'est que lorsque vous commencez à vous plonger dans les eval
, substitute
etc. si vous savez vraiment ce que vous faites.