Cette réponse couvrira un grand nombre des mêmes éléments que les réponses existantes, mais cette question (en passant les noms de colonnes à des fonctions) vient assez souvent que je voulais qu'il y ait une réponse qui a couvert les choses un peu plus complètement.
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
.
Un bloc d'achoppement très commun ici est qu'un naturel (mais incorrect) La tentative 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 df$col1
n'évalue pas l'expression col1
. Il cherche simplement une colonne au df
appelée littéralement col1
. Ce comportement est décrit dans ?Extract
sous la section "Objets récursifs (semblables à une liste)".
La plus simple et la solution la plus souvent recommandée est tout simplement passer de $
à [[
et passer 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 « meilleure pratique » puisqu'elle est la méthode qui est le 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. Beaucoup de paquets populaires font usage de ce genre de techniques, mais en les utilisant, il faut plus de soin et de compétence, car ils peuvent introduire des complexités subtiles et des points d'échec imprévus. This section de Hadley's Advanced R livre est une excellente référence pour certains de ces problèmes.
Si vous vraiment voulez enregistrer l'utilisateur de taper toutes ces citations, une option pourrait consister à convertir les noms de colonnes nues, sans guillemets 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, un peu idiot probablement, puisque 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. Pour finir, si nous voulons obtenir vraiment fantaisie, nous pourrions décider que plutôt que de passer dans 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 recourons à utiliser eval()
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, je me sers encore deparse(substitute())
le nom de la nouvelle colonne. Ici, toutes les suivantes sont utilisables:
> 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
Donc, la réponse courte est essentiellement: passer data.frame noms de colonnes sous forme de chaînes et d'utiliser [[
pour sélectionner une seule colonne.Seulement commencer à fouiller dans eval
, substitute
, etc. si vous savez vraiment ce que vous faites.
Y at-il un moyen de transmettre le nom de la colonne pas comme une chaîne? – kmm
Vous devez soit transmettre le nom de colonne indiqué en tant que caractère, soit l'index d'entier de la colonne. Le simple fait de passer 'B' supposera que B est un objet lui-même. – Shane
Je vois. Je ne suis pas sûr de la façon dont j'ai fini avec le substitut alambiqué, eval, etc. – kmm