2013-10-02 17 views
17

Zauważyłem, że sporo pakietów pozwala przekazywać nazwy symboli, które mogą nie być poprawne nawet w kontekście, w którym funkcja jest wywoływana. Zastanawiam się, jak to działa i jak mogę go użyć w moim własnym kodzie?Przekazywanie nazwy zmiennej do funkcji w R

Oto przykład z ggplot2:

a <- data.frame(x=1:10,y=1:10) 
library(ggplot2) 
qplot(data=a,x=x,y=y) 

x i y nie istnieją w moim nazw, ale ggplot rozumie, że są one częścią ramki danych i opóźnia ich oceny w kontekście, w którym są ważne. Próbowałem robić to samo:

b <- function(data,name) { within(data,print(name)) } 
b(a,x) 

to jednak nie zdało egzaminu:

Error in print(name) : object 'x' not found 

Co robię źle? Jak to działa?

Uwaga: to nie duplikatem Pass variable name to a function in r

Odpowiedz

13

wiem, że jest to starszy wątek, ale jest jeden mam, o których mowa w przeszłości. Niedawno odkryłem, co uważam za lepsze podejście do przekazywania nazw zmiennych. Więc pomyślałem, że to załapię. Mam nadzieję, że to pomoże komuś.

a <- data.frame(x = 1:10, y = 1:10) 

b <- function(df, name){ 
    eval(substitute(name), df) 
} 

b(a, x) 
    [1] 1 2 3 4 5 6 7 8 9 10 

Aktualizacja Podejście używa non ocenę standardowe. Zacząłem wyjaśniać, ale szybko zdałem sobie sprawę, że Hadley Wickham robi to znacznie lepiej niż ja. Przeczytaj ten artykuł: http://adv-r.had.co.nz/Computing-on-the-language.html

+1

Czy mógłbyś podać nieco więcej szczegółów (dodać kilka komentarzy)? To podejście brzmi interesująco. Zauważ, że nie ma "starych wątków" na przepełnieniu stosu, informacja jest zachowywana dla ludzi takich jak ty i ja, którzy pytają google. –

+1

@static_rtti Zaktualizowałem odpowiedź. HTH –

+1

To jest klejnot odpowiedzi, dziękuję. Jeśli to pomaga, to jeśli 'var <- eval (substitute (var), data)' daje obiekt, to 'var.name <- substitute (var)' podaje nazwę zmiennej przekazanej do użycia w funkcji. – drstevok

9

Można to zrobić za pomocą match.call na przykład:

b <- function(data,name) { 

    ## match.call return a call containing the specified arguments 
    ## and the function name also 
    ## I convert it to a list , from which I remove the first element(-1) 
    ## which is the function name 

    pars <- as.list(match.call()[-1]) 
    data[,as.character(pars$name)] 

} 

b(mtcars,cyl) 
[1] 6 6 4 6 8 6 8 4 4 6 6 8 8 8 8 8 8 4 4 4 4 8 8 8 8 4 4 4 8 6 8 4 

wyjaśnienie:

match.call zwracającej wywołanie, w którym wszystkie podane argumenty są określone według ich pełnych nazw.

Więc wyjście match.call wynosi 2 symbole:

b <- function(data,name) { 
    str(as.list(match.call()[-1])) ## I am using str to get the type and name 
} 

b(mtcars,cyl) 
List of 2 
$ data: symbol mtcars 
$ name: symbol cyl 

Więc używam pierwsze mtcars symbol ansd przekonwertować sekund na łańcuch:

mtcars[,"cyl"] 

lub równoważne:

eval(pars$data)[,as.character(pars$name)] 
+0

Czy możesz wyjaśnić nieco, jak to działa? –

+1

@static_rtti Dodaję pewne wyjaśnienie. Mam nadzieję, że teraz jest jaśniej. – agstudy

+0

Dzięki, teraz jest o wiele jaśniej. Wciąż chciałbym zrozumieć, dlaczego moja wersja zawodzi. –

0

Jeśli jesteś umieścić nazwę zmiennej między cytatami podczas wywoływania funkcji, to działa:

> b <- function(data,name) { within(data,print(name)) } 
> b(a, "x") 
[1] "x" 
    x y 
1 1 1 
2 2 2 
3 3 3 
4 4 4 
5 5 5 
6 6 6 
7 7 7 
8 8 8 
9 9 9 
10 10 10 
Powiązane problemy