2011-12-05 25 views
5

Chciałbym napisać wrapper wokół niestandardowej funkcji, która pobiera kilka wektorów jako dane wejściowe (jak: mtcars$hp, mtcars$am itp.) Do podjęcia danych wejściowych jako nazwa ramki danych (jako parametr data, np .: mtcars) i nazwy zmiennych (jak: hp i am), jak zwykle w większości standardowych funkcji.`Z` użycie wewnątrz funkcji (opakowanie)

Ale mam pewne problemy, mój zaproponował funkcja 'demo' (owinięcie wokół mean nie działa

kod:.

f <- function(x, data=NULL) { 
    if (!missing(data)) { 
     with(data, mean(x)) 
    } else { 
     mean(x) 
    } 
} 

Running przeciwko robót wektora kursu:

> f(mtcars$hp) 
[1] 146.69 

Ale with nie powiodło się niestety:

> f(hp, mtcars) 
Error in with(d, mean(x)) : object 'hp' not found 

Choć w globalnym środowisku/bez mój zwyczaj funkcja działa prawo:

> with(mtcars, mean(hp)) 
[1] 146.69 

Próbowałem zrobić jakiś eksperyment z substitute, deparse i innych, ale bez powodzenia. Każda wskazówka byłaby mile widziany!

+5

Zobacz artykuł na temat @Hadley Wickham na stronie: https://github.com/hadley/devtools/wiki/Evaluation – Andrie

+1

Czy nie powinno to być 'f (hp, mtcars)'? – James

+1

Inną opcją, którą możesz chcieć zbadać, jest użycie formuły, więc nazwałbyś ją nieco inaczej - foo (~ hp, mtcars) - a następnie użyj rzeczy takich jak model.frame, aby uzyskać wartości. – Spacedman

Odpowiedz

10

Oto klucz element układanki:

f <- function(x,data=NULL) { 
    eval(match.call()$x,data) # this is mtcars$hp, so just take the mean of it or whatever 
} 

> f(hp,mtcars) 
[1] 110 110 93 110 175 105 245 62 95 123 123 180 180 180 205 215 230 66 52 65 97 150 150 245 175 66 
[27] 91 113 264 175 335 109 

# it even works without a data.frame specified: 
> f(seq(10)) 
[1] 1 2 3 4 5 6 7 8 9 10 

Zobacz @ linku Andrie do @ dokumentu Hadley za wyjaśnienie dlaczego to działa. Zobacz uwaga @ Hadley'a dla krytycznego zastrzeżenia: f() nie można uruchomić z innej funkcji.

Zasadniczo R używa leniwej oceny (np. Nie ocenia rzeczy, dopóki nie są faktycznie używane). Więc możesz uciec z przekazaniem go hp, ponieważ pozostaje on symbolem nieocenionym, dopóki nie pojawi się gdzieś. Od match.call chwyta to jako symbol i czeka na ocenę, wszystko jest dobrze.

Następnie eval ocenia je w określonym środowisku. Według ?eval, drugi argument reprezentuje:

Środowisko, w którym expr ma być oceniony. Może również mieć wartość NULL, listę , ramkę danych, parę lub liczbę całkowitą podaną dla sys.call.

Dlatego jesteś w dobrej formie z NULL (jeśli nie przekazujesz danych.frame) lub data.frame.

Dowód oceny leniwy jest to, że nie zwraca błąd (ponieważ x nigdy nie jest używany w funkcji):

> g <- function(x) { 
+ 0 
+ } 
> g(hp) 
[1] 0 
+0

Co za elegancki idiom. Dzięki tobie (i Hadley) za to. –

+0

Głównie Hadley. Przypomniałem sobie, ale nie na tyle precyzyjnie, by wyciągnąć go z kapelusza bez odniesienia do jego (niesamowitej) wiki. –

+0

Bardzo porządnie. Podsumowując, każdy pRoblem jest związany z RT (F) M ... – aL3xa

-1

spróbuj tego:

f <- function(x, data = NULL) { 
    if (is.null(data)) { 
     mean(x) 
    } else { 
     attach(data) 
     mean(x) 
     detach(data) 
    } 
} 

Także w Twojej przykład wpisać dane określone zamiast kolumny. Twój przykład należy F (hp, mtcars)

+0

Przyjemny wysiłek, ale brakuje nawiasu i nie jestem pewien, czy wolałbym 'attach' na' with', i to 'f (hp, mtcars)' nadal kończy się niepowodzeniem z "hp not found". –

3
f <- function(x, data=NULL) { 
    if (!missing(data)) { colname=deparse(substitute(x)) 
     mean(data[[colname]]) 
    } else { 
     mean(x) 
    } 
} 

f(hp, mtcars) 
[1] 146.6875 

(Co prawda nie tak zwarty jak @ GSK i myślę Postaram się zapamiętać jego metodę nad moją i dzięki Joshowi O'Brienowi za wskazanie błędu, który został już naprawiony.)

+0

Dziękuję @DWin za ten hack! – daroczig

Powiązane problemy