2015-09-09 43 views
14

W treści niektórych funkcji R, na przykład lm, widzę połączenia z funkcją match.call. Jak mówi strona pomocy, gdy jest używana wewnątrz funkcji match.call, zwraca wywołanie, w którym podane są nazwy argumentów; i ma to być przydatne do przekazywania dużej liczby argumentów do innych funkcji.Dlaczego funkcja match.call jest przydatna?

Na przykład w funkcji lm widzimy wywołanie funkcji model.frame

function (formula, data, subset, weights, na.action, method = "qr", 
model = TRUE, x = FALSE, y = FALSE, qr = TRUE, singular.ok = TRUE, 
contrasts = NULL, offset, ...) 
{ 
cl <- match.call() 
mf <- match.call(expand.dots = FALSE) 
m <- match(c("formula", "data", "subset", "weights", "na.action", 
    "offset"), names(mf), 0L) 
mf <- mf[c(1L, m)] 

mf$drop.unused.levels <- TRUE 
mf[[1L]] <- quote(stats::model.frame) 
mf <- eval(mf, parent.frame()) 

Dlaczego jest to bardziej przydatne niż czyni prostą wezwanie do model.frame określające nazwy argumentów jak zrobić dalej?

function (formula, data, subset, weights, na.action, method = "qr", 
model = TRUE, x = FALSE, y = FALSE, qr = TRUE, singular.ok = TRUE, 
contrasts = NULL, offset, ...) 
{ 
mf <- model.frame(formula = formula, data = data, 
        subset = subset, weights = weights, subset = subset) 

Zauważ, że match.call ma inne zastosowanie, że nie dyskutować, przechowywania połączenie w powstałego obiektu.

+6

Po pierwsze, nie zapisuj tego wszystkiego. Możesz zrobić takie rzeczy, jak przekazanie wszystkich argumentów naraz, coś w stylu 'f <- function (x, y, z) do.call (" sum ", as.list (match.call() [- 1])); f (1, 2, 3) ## [1] 6'. Oczywiście byłoby to o wiele bardziej przydatne dla długiej listy nazwanych argumentów. –

+0

Dość sprawiedliwe, myślę, że możesz również zrobić odwrotne przekrojenie argumentów. 'f <- function (x, y, z) {l <- as.list (match.call()) [- 1]; do.call (sum, l [setdiff (names (l), 'z') ])} '. W każdym razie, myślę, że byłem zdezorientowany co do użycia w 'lm'. Jednak uważam, że wszystko jest możliwe do rozwiązania za pomocą argumentu "..." dość łatwo. Chyba jestem wybredna. – Usobi

+2

@Usobi: Czy 'match.call()' jest bardziej odporne w następującym sensie? Jeśli użyjesz '...', wtedy nie wiesz, jakie argumenty zostaną przekazane, i możesz skończyć z tym, że rzeczy, których nie chcesz, lub które nie są potrzebne, lub które łamią rzeczy w nieoczekiwany sposób. Z drugiej strony, jeśli jawnie powtórzysz nazwy argumentów, aby je przekazać, to utrudni to kod, jeśli zmienisz definicje argumentów funkcji. – peterthinking

Odpowiedz

7

Jednym z powodów jest to, że match.call przechwytuje język połączenia bez jego oceny, w tym przypadku umożliwia lm potraktowanie niektórych "brakujących" zmiennych jako "opcjonalne". Rozważmy:

lm(x ~ y, data.frame(x=1:10, y=runif(10))) 

kontra

lm2 <- function (
    formula, data, subset, weights, na.action, method = "qr", 
    model = TRUE, x = FALSE, y = FALSE, qr = TRUE, singular.ok = TRUE, 
    contrasts = NULL, offset, ... 
) { 
    mf <- model.frame(
    formula = formula, data = data, subset = subset, weights = weights 
) 
} 
lm2(x ~ y, data.frame(x=1:10, y=runif(10))) 
## Error in model.frame.default(formula = formula, data = data, subset = subset, : 
## invalid type (closure) for variable '(weights)' 

W lm2, ponieważ weights jest "brak", ale nadal go używać w weights=weights, R próbuje użyć funkcji stats::weights który wyraźnie nie to, co było zamierzone. Możesz obejść to, sprawdzając brakujące dane, zanim zadzwonisz pod numer model.frame, ale w tym momencie match.call zaczyna wyglądać całkiem nieźle. Spójrz na to, co się stanie, jeśli debug wezwanie:

debug(lm2) 
lm2(x ~ y, data.frame(x=1:10, y=runif(10))) 
## debugging in: lm2(x ~ y, data.frame(x = 1:10, y = runif(10))) 
## debug at #5: { 
##  mf <- model.frame(formula = formula, data = data, subset = subset, 
##   weights = weights) 
## } 
Browse[2]> match.call() 
## lm2(formula = x ~ y, data = data.frame(x = 1:10, y = runif(10))) 

match.call nie wiąże brakujących argumentów w ogóle.

Można argumentować, że opcjonalne argumenty powinny być jawnie opcjonalne za pomocą wartości domyślnych, ale nie to się tutaj stało.