Cette réponse couvrira bon nombre des mêmes éléments que les réponses existantes, mais ce problème (passer les noms de colonnes aux fonctions) revient assez souvent pour que je souhaite qu'il y ait une réponse qui couvre les choses de manière un peu plus complète.
Supposons que nous ayons une trame 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
et y
.
Une pierre d'achoppement très courante ici 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 ici est que cela df$col1
n'évalue pas l'expression col1
. Il recherche simplement une colonne df
littéralement appelée col1
. Ce comportement est décrit dans ?Extract
la section "Objets récursifs (de type liste)".
La solution la plus simple et la plus souvent recommandée consiste simplement à passer de $
à [[
et à transmettre les arguments de la fonction sous forme de chaînes:
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
Ceci est souvent considéré comme une «meilleure pratique» car c'est la méthode la plus difficile à bousiller. Passer les noms de colonnes sous forme de chaînes est à peu près aussi clair que possible.
Les deux options suivantes sont plus avancées. De nombreux forfaits les plus populaires utilisent ce genre de techniques, mais leur utilisation bien nécessite plus de soins et de compétences, car ils peuvent introduire des complexités subtiles et des points imprévus d'échec. Cette section du livre Advanced R de Hadley est une excellente référence pour certains de ces problèmes.
Si vous voulez vraiment éviter à l'utilisateur de taper tous ces guillemets, une option peut être de convertir les noms de colonnes nus et sans guillemets en chaînes en utilisant 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, probablement un peu idiot, car nous faisons vraiment la même chose que dans new_column1
, juste avec un tas de travail supplémentaire pour convertir les noms nus en chaînes.
Enfin, si nous voulons vraiment avoir de la fantaisie, nous pourrions décider qu'au lieu de passer les noms de deux colonnes à ajouter, nous aimerions être plus flexibles et permettre d'autres combinaisons de deux variables. Dans ce cas, nous aurions probablement recours à l'utilisation eval()
d'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
}
Juste pour le plaisir, j'utilise toujours deparse(substitute())
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
La réponse courte est donc essentiellement: passez les noms de colonnes data.frame sous forme de chaînes et utilisez [[
pour sélectionner des colonnes uniques. Commencer à ne se plonger dans eval
, substitute
etc. si vous savez vraiment ce que vous faites.