2011-05-19 18 views
6

Estoy luchando por entender por qué esto no funciona.¿Cómo usar con/dentro de una función?

df <- data.frame(a=1:10, b=1:10) 

foo <- function(obj, col) { 
    with(obj, ls()) 
    with(obj, print(col)) 
} 
foo(df, a) 

[1] "a" "b"

error en la impresión (col): objeto 'a' no encontrado

Si esto hace el trabajo:

with(df, print(a)) 
+1

Probablemente sea útil tener un contexto más amplio sobre lo que está tratando de lograr. –

Respuesta

12

with es útil y mejora la legibilidad en una contexto interactivo, pero puede dañar su cerebro en un contexto de programación en el que está pasando cosas de un lado a otro a funciones y tratando cosas en diferentes entornos. En general, dentro de R, el uso de símbolos en lugar de nombres es una especie de "azúcar semántica" que es conveniente y legible en el uso interactivo, pero ligeramente obsoleto para la programación [p. $, subset]). Si usted está dispuesto a comprometer por lo que el uso de un nombre ("a") en lugar de un símbolo (a) entonces sugeriría caer de nuevo a la más simple obj[[col]] en lugar de utilizar with aquí ...

Por lo tanto, como un auto -contained respuesta:

foo <- function(object,col) { 
    print(names(object)) 
    print(object[[col]]) 
} 

Si quería para permitir múltiples columnas (es decir, un vector de caracteres)

foo <- function(object,col) { 
    print(names(object)) 
    print(object[col]) 
} 

edición: REFRA desde el uso de subset con una función, en la sugerencia de @ hadley

(esto imprimirá la respuesta como un marco de datos, incluso si se selecciona una sola columna, que puede no ser la que desea).

+0

eliminé mi respuesta, por lo que es posible que desee cambiar la referencia. Y +1 para la advertencia. –

+0

Gracias por todas las respuestas. No estoy tratando de imprimir nada, solo quiero transferir la columna a otras funciones. Al observar funciones como subconjuntos que toman columnas como nombres de variables, no como cadenas, pensé que sería fácil hacer lo mismo. Supongo que me quedaré con la transmisión de cadenas. :) – rafalotufo

+0

Excepto que el uso de un subconjunto dentro de una función es incorrecto, porque obtendrá mensajes de error confusos si las columnas no son las esperadas, es mejor utilizar subconjuntos rectos. – hadley

4

Cualquier cosa que se pase a una función debe ser un objeto, una cadena o un número. Hay dos problemas con esto:

  1. En este caso, está tratando de pasar "a" como un objeto, cuando realmente debería pasarlo como una cadena.
  2. con (obj, ls())) volverá al entorno de funciones (función de ámbito) y no a la pantalla a menos que le indique que imprima.

Lo que queremos es más como:

foo <- function(obj, col) { 
     print(with(obj, ls())) 
     with(obj, print(obj[[col]])) 
    } 

foo(df, "a") 

o si sólo está buscando una columna a imprimir:

foo <- function(obj, col) { 
      with(obj, print(obj[[col]])) 
     } 

foo(df, "a") 
+0

Pero eso no es lo que él quiere: quiere que se imprima df $ a. –

+0

No está claro lo que quiere imprimir. Para mí, parece que quiere dos líneas impresas. Uno con los colnames del obj y otro con los contenidos de la columna especificada. –

1

En el argumento de la función col se evalúa antes de usar en la función con (eso opuesto al uso interactivo). Aquí tienes dos soluciones a este problema.

foo1 <- function(obj, col) { 
      with(obj, print(eval(col))) 
     } 
foo1(mydf, quote(a))# here you have to remember to quote argument 


foo2 <- function(obj, col) { 
      col <- as.expression(as.name(substitute(col)))#corrected after DWIN comment 
      with(obj, print(eval(col))) 
     } 
foo2(mydf, a)# this function does all necessary stuff 
+0

+1 por responder a la pregunta tal como se planteó, aunque sigo pensando que jugar con/eval/etc. de esta manera es una mala idea ... –

+0

No pude conseguir el segundo de ellos para trabajar. En general, cuando usa 'eval', necesita especificar un entorno. –

Cuestiones relacionadas