Esta respuesta cubrirá muchos de los mismos elementos que las respuestas existentes, pero este problema (pasar los nombres de las columnas a las funciones) surge con tanta frecuencia que quería que hubiera una respuesta que cubriera las cosas de manera un poco más completa.
Supongamos que tenemos un marco de datos muy simple:
dat <- data.frame(x = 1:4,
y = 5:8)
y nos gustaría escribir una función que cree una nueva columna z
que es la suma de las columnas x
y y
.
Un obstáculo muy común aquí es que un intento natural (pero incorrecto) a menudo se ve así:
foo <- function(df,col_name,col1,col2){
df$col_name <- df$col1 + df$col2
df
}
#Call foo() like this:
foo(dat,z,x,y)
El problema aquí es que df$col1
no evalúa la expresión col1
. Simplemente busca una columna en df
literalmente llamada col1
. Este comportamiento se describe en ?Extract
la sección "Objetos recursivos (en forma de lista)".
La solución más simple, y más a menudo simplemente se recomienda cambiar de $
a [[
y pasar los argumentos de la función como cadenas:
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
Esto a menudo se considera "mejor práctica", ya que es el método más difícil de estropear. Pasar los nombres de las columnas como cadenas es lo más inequívoco posible.
Las siguientes dos opciones son más avanzadas. Muchos paquetes populares hacen uso de este tipo de técnicas, pero usarlas bien requiere más cuidado y habilidad, ya que pueden introducir complejidades sutiles y puntos de falla imprevistos. Esta sección del libro Advanced R de Hadley es una excelente referencia para algunos de estos temas.
Si realmente desea evitar que el usuario escriba todas esas comillas, una opción podría ser convertir los nombres de columnas desnudos y sin comillas en cadenas usando 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
Esto es, francamente, probablemente un poco tonto, ya que en realidad estamos haciendo lo mismo que en new_column1
, solo que con un montón de trabajo extra para convertir nombres desnudos en cadenas.
Finalmente, si queremos ser realmente sofisticados, podemos decidir que en lugar de pasar los nombres de dos columnas para agregar, nos gustaría ser más flexibles y permitir otras combinaciones de dos variables. En ese caso, probablemente recurriremos al uso eval()
de una expresión que involucre las dos columnas:
new_column3 <- function(df,col_name,expr){
col_name <- deparse(substitute(col_name))
df[[col_name]] <- eval(substitute(expr),df,parent.frame())
df
}
Solo por diversión, todavía lo estoy usando deparse(substitute())
para el nombre de la nueva columna. Aquí, todo lo siguiente funcionará:
> 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
Entonces, la respuesta corta es básicamente: pasar los nombres de las columnas data.frame como cadenas y usarlos [[
para seleccionar columnas individuales. Sólo empezar a ahondar en eval
, substitute
, etc, si usted realmente sabe lo que está haciendo.